正如Does initialization entail lvalue-to-rvalue conversion? Is int x = x;
UB?中所述,C ++标准在3.3.2
声明部分中有一个令人惊讶的例子,其中int
用它初始化'自己的不确定值:
int x = 12; { int x = x; }
这里第二个x用它自己的(不确定的)值初始化。 - 结束示例]
Johannes对此问题的回答表明是未定义的行为,因为它需要左值到右值的转换。
在最新的C ++ 14草案标准N3936
中可找到here,此示例已更改为:
unsigned char x = 12; { unsigned char x = x; }
这里第二个x用它自己的(不确定的)值初始化。 - 结束示例]
C ++ 14中有关于不确定值和未定义行为的更改,这些行为已在示例中推动了此更改吗?
答案 0 :(得分:53)
是的,这种变化是由语言的变化驱动的,如果评估产生了一个不确定的值,那么它会使其成为未定义的行为,但无符号的窄字符有一些例外
Defect report 1787其建议的文字可以在N3914 1 中找到recently accepted in 2014,并纳入最新的工作草案N3936
:
关于不确定值的最有趣的变化是8.5
段 12 来自:
如果没有为对象指定初始化程序,则默认初始化该对象;如果未执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。 [注意:具有静态或线程存储持续时间的对象为零初始化,请参见3.6.2。 - 结束记录]
to(强调我的):
如果没有为对象指定初始化程序,则该对象为 默认初始化。使用自动或自动存储对象时 获得动态存储持续时间,该对象具有不确定 值,如果没有为对象执行初始化,那么 对象保留不确定的值,直到替换该值 (5.17 [expr.ass])。 [注意:具有静态或线程存储的对象 持续时间为零初始化,见3.6.2 [basic.start.init]。 -结束 note] 如果评估产生了不确定的值,那么 除以下情况外,行为未定义:
如果通过以下评估产生无符号窄字符类型(3.9.1 [basic.fundamental])的不确定值:
条件表达式的第二个或第三个操作数(5.16 [expr.cond]),
逗号的右操作数(5.18 [expr.comma]),
转换或转换为无符号窄字符类型的操作数(4.7 [conv.integral],5.2.3 [expr.type.conv],5.2.9 [expr.static.cast],5.4 [expr.cast])或
废弃值表达式(第5条[expr]),
然后操作的结果是一个不确定的值。
如果通过评估权利产生无符号窄字符类型(3.9.1 [basic.fundamental])的不确定值 一个简单赋值运算符的操作数(5.17 [expr.ass]),它的第一个 操作数是无符号窄字符类型的左值 indeterminate值替换引用的对象的值 左操作数。
如果通过评估产生无符号窄字符类型(3.9.1 [basic.fundamental])的不确定值 初始化unsigned对象时的初始化表达式 窄字符类型,该对象初始化为不确定 值。强>
并包含以下示例:
[示例:
int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true }
- 结束示例]
我们可以在N3936中找到此文本,这是当前的working draft,而N3937
是C++14 DIS
。
在C ++之前
值得注意的是,在此草案之前,与C which has always had a well specified notion of what uses of indeterminate values were undefined不同,C ++使用术语“不确定值”,甚至没有定义它( assuming we can not borrow definition from C99 )以及{{3} }。我们不得不依赖4.1
see defect report 616部分1787
所涵盖的underspecified lvalue-to-rvalue conversion部分{{1}} Lvalue-to-rvalue转换段落 1 表示:
[...]如果对象未初始化,则需要进行此转换的程序具有未定义的行为。[...]
脚注: