C ++标准是否在C ++ 14中使用了不确定的值和未定义的行为?

如在初始化中涉及左值到右值的转换? 是int x = x; UB? C ++标准在第3.3.2的声明中有一个令人惊讶的例子,其中一个int用它自己的不确定值进行初始化:

 int x = 12; { int x = x; } 

这里第二个x是用自己的(不确定的)值初始化的。 – 结束示例 ]

哪个Johannes回答这个问题表明是未定义的行为,因为它需要一个左值到右值的转换。

在最新的C ++ 14草案标准N3936可以在这里find这个例子已经改为:

 unsigned char x = 12; { unsigned char x = x; } 

这里第二个x是用自己的(不确定的)值初始化的。 – 结束示例 ]

在C ++ 14中,在不确定的值和未定义的行为方面有什么改变,导致了这个例子的改变?

是的,这种变化是由语言的变化引起的, 如果评估产生了一个不确定的值,但是对于无符号的窄字符则有一些例外,这种变化使得它不确定。

缺陷报告1787其build议案文可在N3914 1中find, 最近在2014年被接受,并纳入最新的工作草案N3936

关于不确定价值的最有趣的变化是8.5节第12段:

如果没有为对象指定初始化程序,则该对象将被默认初始化; 如果未执行初始化,则具有自动或dynamic存储持续时间的对象具有不确定的值。 [ 注意:具有静态或线程存储时间的对象是零初始化的,见3.6.2。 – 结束注意 ]

强调我的 ):

如果没有为对象指定初始化程序,则该对象将被默认初始化。 当获得具有自动或dynamic存储持续时间的对象的存储时,对象具有不确定的值 ,并且如果没有对该对象执行初始化,那么该对象将保留不确定的值,直到该值被replace为止(5.17 [expr.ass]) 。 [注意:具有静态或线程存储时间的对象是零初始化的,参见3.6.2 [basic.start.init]。 – 注意] 如果评估产生了不确定的值,除非在以下情况下,行为是不确定的

  • 如果通过以下评估产生了无符号的窄字符types(3.9.1 [basic.fundamental])的不确定值:

    • 条件expression式(5.16 [expr.cond])的第二个或第三个操作数,

    • 一个逗号的右操作数(5.18 [expr.comma]),

    • 转换为无符号的窄字符types(4.7 [conv.integral],5.2.3 [expr.type.conv],5.2.9 [expr.static.cast],5.4 [expr.cast])的操作数, 要么

    • 丢弃值expression式(条款5 [expr]),

    那么操作的结果是一个不确定的值。

  • 如果通过简单赋值运算符(5.17 [expr.ass])的右操作数的求值产生无符号的窄字符types(3.9.1 [basic.fundamental])的不确定值(第一个操作数是无符号窄左值)字符types时,不确定的值将replace左操作数引用的对象的值。

  • 如果在初始化无符号的窄字符types的对象时通过初始化expression式的求值产生了无符号的窄字符types(3.9.1 [basic.fundamental])的不确定值,则该对象被初始化为不确定的值。

并包含以下示例:

[ 例如:

 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 } 

结束示例 ]

我们可以在目前的工作草案 N3937find这个文本, N3937C++14 DIS

在C ++之前1y

有趣的是,在这个草案之前,不同于C 一直有一个明确的概念,说明不确定值的用法是未定义的, C ++使用了不确定值这个术语,甚至没有定义它( 假设我们不能从C99借用定义 ) 参见缺陷报告616 。 我们不得不依赖在C ++ 11标准草案中 低估的左值到右值的转换 ,在4.1左值到右值转换的1段中讲到

如果该对象未初始化,则需要此转换的程序具有未定义的行为。[…]


脚注:

  1. 1787是一个缺陷报告616的修订,我们可以在N3903中find这个信息