c++标准在c++ 14中对不确定值和未定义行为的使用方面有改变吗?

Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?

本文关键字:c++ 方面 改变 未定义 标准 不确定      更新时间:2023-10-16

如初始化是否需要左值到右值转换中所述?int x = x;是UB吗?c++标准在3.3.2 声明点一节中有一个令人惊讶的例子,其中int用它自己的不确定值初始化:

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

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

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

在最新的c++ 14标准草案N3936中,可以在这里找到这个例子已经更改为:

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

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

在c++ 14中,关于不确定的值和未定义的行为是否发生了一些变化,这些变化导致了示例中的变化?

是的,这种变化是由语言的变化所驱动的,如果计算产生一个不确定的值,那么它就是未定义行为,但是对于无符号窄字符有一些例外。

缺陷报告1787,其建议文本可在N39141中找到,最近于2014年被接受,并纳入最新的工作草案N3936:

关于不确定值最有趣的变化是8.512,从

如果对象没有指定初始化式,则默认初始化该对象;如果不进行初始化,自动或动态存储时长的对象的值不确定。[注意:具有静态或线程存储时间的对象是零初始化的,参见3.6.2。- 结束说明]

to (强调mine):

如果没有为对象指定初始化式,则该对象为default-initialized。当存储对象具有自动或获取动态存储时间,对象有一个不确定值,如果未对该对象进行初始化,则为对象保留一个不确定的值,直到该值被替换(5.17 [expr.ass])。[注意:具有静态或线程存储的对象。Duration为零初始化,参见3.6.2 [basic.start.init]。端如果求值产生一个不确定的值,则行为是未定义的,除了以下情况:

  • 如果unsigned窄字符类型(3.9.1 [basic.fundamental])的不确定值由:

    求值产生
    • 条件表达式(5.16 [expr.cond])的第二个或第三个操作数,

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

    • 强制转换或转换为无符号窄字符类型的操作数(4.7 [convr .integral], 5.2.3 [expr.type. type])。conv], 5.2.9[expr.static。[expr.cast]、5.4 [expr.cast])或

    • 一个丢弃值表达式(条款5 [expr]),

    则操作的结果为不确定值

  • 如果右求值产生unsigned窄字符类型(3.9.1 [basic.fundamental])的不确定值简单赋值操作符(5.17 [expr.ass])的操作数,其第一个操作数是无符号窄字符类型的左值不确定的值将替换引用的对象的值

  • 如果unsigned窄字符类型(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中找到这个文本,这是当前的工作草案,N3937C++14 DIS

c++ 1y

值得注意的是,在此草案之前,不像C总是有一个很好的定义不确定值的概念,c++使用术语不确定值甚至没有定义它(假设我们不能从C99中借用定义),也可以看到缺陷报告616。我们必须依赖于未明确规定的左值到右值转换,在c++ 11标准草案中,4.1 左值到右值转换段落1中有涉及,其中说:

[…[…]

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

脚注:

  1. 1787是缺陷报告616的修订版,我们可以在N3903
  2. 中找到信息