在哪些情况下 std::optional operator == 会导致未定义的行为?

Posted

技术标签:

【中文标题】在哪些情况下 std::optional operator == 会导致未定义的行为?【英文标题】:In which cases does std::optional operator == cause undefined behavior? 【发布时间】:2020-10-13 12:46:44 【问题描述】:

Cppreference 对std::optional 的混合(可选和一些其他非可选类型)比较运算符有以下描述:

将 opt 与一个值进行比较。值进行比较(使用 T) 的对应运算符仅当 opt 包含值时。否则, opt 被认为小于值。如果对应的两路 *opt 和 value 之间的比较表达式格式不正确,或者如果 其结果不可转换为 bool,行为未定义。

让我困惑的是:

这些不规范的比较有哪些例子?

为什么编译器/STL 不直接拒绝无效的比较而不是给我们 UB?

【问题讨论】:

只是猜测:T 有一个奇怪的T::operator== 或者根本没有operator==?不知道为什么它是 UB 而不是格式错误... 【参考方案1】:

这源于不精确的规范,此后已得到纠正。

在C++17 中,这些比较被指定为:

要求*x == *y 的表达式应该是格式良好的,并且它的结果应该可以转换为bool

Requires 是一个先决条件,因此不满足这些条件将是undefined behavior。但是有许多不同种类的“先决条件”——这是否意味着静态检查,这是否意味着如果条件不满足,则将运算符从重载集中删除,是否意味着实际的未定义行为?

在C++20 中,这些被指定为:

授权:表达式*x == *y 是格式良好的,其结果可转换为bool

如果不满足条件,哪个means 程序格式错误。基本上,授权是static_assert(或等效项)。

所以,是的,标准库有义务拒绝比较不存在或没有给你类似bool 的类型。这实际上永远不会给您带来未定义的行为(如果没有这样的运算符,实现会做什么,从/dev/random 读一点?)但现在它被更明确地指定了。


这些更改来自 Marshall Clow 题为“Mandating the Standard Library”的一系列论文,这篇论文特别来自 P1460(感谢 Marshall!)。用于指定标准库的新术语来自 Walter Brown 的“Guidelines for Formulating Library Semantics Specifications”论文 (P1369)。

【讨论】:

赞成,但我不确定你为什么引用取消引用 x 和 y 的规范,我想如果我询问只有一侧被取消引用。我认为这个限制也是为了比较 optional 和 optional 所以答案仍然有相同的结论。 @NoSenseEtAl 因为所有比较的措辞都相同,所以我只选择了第一个。 "如果没有这样的操作符,实现会做什么?"当然,返回FileNotFound

以上是关于在哪些情况下 std::optional operator == 会导致未定义的行为?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 标准是不是允许在没有开销的情况下实现 std::optional<double>

std::optional::value_or() - 惰性参数评估

std::optional 相对于 nullptr 的优点/缺点是啥?

std::optional<T> 的开销?

std::optional 如何永远不会“异常无价值”?

std::optional 成员是不是连续存储?