【问题标题】:Ternary operator with branches with void type带有 void 类型分支的三元运算符
【发布时间】:2017-08-28 16:10:06
【问题描述】:

在返回 void 的函数中使用三元运算符是否安全?像这样的:

void foo1(){}
void foo2(){}

//////////////

bool to_use_1 = ....;
to_use_1 ? foo1() : foo2();

编译器可以删除这段代码吗?假设它将这些函数视为纯函数,并执行删除这些调用的积极优化

【问题讨论】:

  • 如果 to_use_1 为真,则执行 foo1,否则执行 foo2。这是完全安全的。是否愿意取决于您和您的编码标准。
  • "...which delete these calls" 只有在“as-if-rule”下,编译器才能证明 foo1 和/或 foo2 没有副作用。
  • @BoundaryImposition 是对的。
  • 是包含表达式的语句。它总是被评估。另外,foo1(); 也是表达式语句。优化只进行不改变结果的更改(值、返回、副作用,...)。优化不得改变程序行为。

标签: c++ compiler-optimization conditional-operator


【解决方案1】:

首先,编译器将/不应该在逻辑上“删除”任何具有可观察效果的调用(copy elision 除外)。无论优化模式多么激进,这根本就不是它被允许做的事情。

事实上,C++ 标准明确允许条件运算符的操作数的结果为void,因此这是预期且安全的。但是,它必须是两者

[C++14: 5.16/1]: 条件表达式从右到左分组。第一个表达式根据上下文转换为 bool(第 4 条)。 求值,如果为真,则条件表达式的结果为第二个表达式的值,否则为第三个表达式的值。仅计算第二个和第三个表达式中的一个。 与第一个表达式关联的每个值计算和副作用都在与第二个或第三个表达式关联的每个值计算和副作用之前排序。

[C++14: 5.16/2]: 如果第二个或第三个操作数的类型为void,则应满足以下条件之一:

  • 第二个或第三个操作数(但不是两者)是一个(可能带括号的)throw-expression (15.1);结果是对方的类型和值类别。

  • 第二个和第三个操作数的类型都是void;结果是void 类型并且是prvalue。 [ 注意: 这包括两个操作数都是throw-expressions 的情况。 ——尾注]

从技术上讲,这个措辞(在其谈论“值”时)并没有完全说明 恰好第二个和第三个表达式之一被评估,即使这些评估没有“价值” .但从分析的角度来看,这基本上是无可争辩的。 可能这里有一个编辑改进的案例。

请注意,这些都不能保证您的计算机在执行期间实际上会跳转到foo1foo2;在您给出的具体示例中,编译器可以立即看到这两个函数都是空的,并优化掉了整行代码。但这不会影响程序的语义,也不是特定于条件运算符的使用。

【讨论】:

  • 我不同意你的观点,我看到删除复制构造函数有副作用(见复制省略)
  • @LmTinyToon:好的,同意。我已经说得更清楚了。
  • 加 1 用于 C++14 参考(实际上是用于 Emilia Clarke :))
  • 实际上,/6 在其谈论左值到右值的转换时,可能会处理感知到的编辑歧义。但要确认或否认这一点,需要一位比我更好的语言律师。
猜你喜欢
  • 1970-01-01
  • 2017-08-24
  • 2011-12-17
  • 1970-01-01
  • 2023-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多