Sha*_*our 5 c++ undefined-behavior initializer-list language-lawyer
考虑以下代码:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
如果我们使用clang -std=c++03它编译代码,则会产生以下警告(实时示例):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
Run Code Online (Sandbox Code Playgroud)
我不是在提倡这样的代码,但是在另一个问题中出现了类似的代码,并且对于是否根据标准C ++ 11进行定义存在分歧。在C ++ 11中,根据初始化程序中的多个突变是否列出未定义的行为,此行为是定义良好的行为,并且如果我使用该警告,则该警告消失了。-std=c++11
如果我们看一下C ++ 11 之前的标准草案,它没有覆盖initializer-list的相同语言,那么似乎我们剩下的是Chapter 5 Expressions第4段:
除非另有说明,否则未指定各个运算符的操作数和各个表达式的子表达式的求值顺序以及发生副作用的顺序。57)在上一个序列点与下一个序列点之间,标量对象最多应通过表达式的计算修改其存储值。此外,应仅访问先验值以确定要存储的值。对于完整表达式的子表达式的每个允许的排序,都应满足本段的要求;否则,行为是不确定的。
为了使这个未定义,我们似乎必须将其解释count++, count++为一个表达式,因此每个解释都应count++作为一个子表达式,因此,此代码在C ++ 11之前是未定义的吗?
C++11之前的代码并非未定义,但求值顺序未指定。如果我们看一下标准草案部分程序执行第12段说:1.9
完整表达式是不是另一个表达式的子表达式的表达式。[...]
第15段说:
每个完整表达式的求值完成时都有一个序列点12)。
那么问题是是否count++, count++是一个完整表达式,每个表达式count++都是一个子表达式,或者每个表达式都有count++自己的完整表达式,因此每个表达式后面都有序列点?8.5 如果我们从初始化器部分查看此初始化的语法:
initializer-clause:
assignment-expression
{ initializer-list ,opt }
{ }
initializer-list:
initializer-clause
initializer-list , initializer-clause
Run Code Online (Sandbox Code Playgroud)
我们唯一的表达式是赋值表达式,并且,分隔组件是初始化列表的一部分,而不是表达式的一部分,因此每个count++都是完整的表达式,并且每个表达式后面都有一个序列点。
gcc 以下错误报告证实了这种解释,该错误报告与我的代码非常相似(在发现此错误报告之前我想出了我的示例方法):
int count = 23;
int foo[] = { count++, count++, count++ };
Run Code Online (Sandbox Code Playgroud)
最终形成缺陷报告 430,我将引用它:
[...]我相信标准很明确,上面的每个初始化表达式都是一个完整表达式(1.9 [intro.execution]/12-13;另请参阅问题 392),因此每个表达式后面都有一个序列点(1.9 [介绍.执行]/16)。我同意该标准似乎没有规定表达式求值的顺序,也许应该如此。有谁知道有一个编译器不会从左到右计算表达式?
| 归档时间: |
|
| 查看次数: |
491 次 |
| 最近记录: |