C++ 标准是否在 C++14 中关于不确定值和未定义行为的使用发生了变化? [英] Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?

查看:31
本文介绍了C++ 标准是否在 C++14 中关于不确定值和未定义行为的使用发生了变化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

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

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

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

在最新的 C++14 草案标准 N3936 中可以找到 此处 此示例已更改为:

<块引用>

unsigned char x = 12;{ 无符号字符 x = x;}

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

C++14 中关于不确定值和未定义行为的某些变化是否导致了示例中的这种变化?

解决方案

是的,这个变化是由语言的变化驱动的,这使得它的行为不确定如果一个不确定的值是由评估产生的但是除了无符号窄字符的一些例外.

缺陷报告 1787文本可以在 N3914 中找到1最近于 2014 年接受并纳入最新的工作草案N3936:

关于不确定值的最有趣的变化是 8.512 来自:

<块引用>

如果没有为对象指定初始化器,则对象默认初始化;如果不进行初始化,具有自动或动态存储期限的对象具有不确定的值.[ 注意: 具有静态或线程存储期的对象是零初始化的,参见 3.6.2.— 尾注 ]

到(强调我的):

<块引用>

如果没有为对象指定初始化器,则该对象是默认初始化.当存储具有自动或获取动态存储时长,对象有一个不确定值,如果没有对对象进行初始化,那对象保留一个不确定的值,直到该值被替换(5.17 [expr.ass]).[注意:具有静态或线程存储的对象持续时间是零初始化的,参见 3.6.2 [basic.start.init].-结尾注意] 如果评估产生不确定的值,则除以下情况外,行为未定义:

  • 如果无符号窄字符类型 (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]) 的操作数,其第一个操作数是一个无符号窄字符类型的左值,一个不确定值替换引用的对象的值左操作数.

  • 如果无符号窄字符类型 (3.9.1 [basic.fundamental]) 的不确定值是通过对初始化无符号对象时的初始化表达式窄字符类型,该对象被初始化为不确定的价值.

并包含以下示例:

<块引用>

[ 示例:

int f(bool b) {无符号字符 c;无符号字符 d = c;//好的,d 有一个不确定的值内部 e = d;//未定义的行为返回 b ?d:0;//如果 b 为真,则未定义行为}

结束示例 ]

我们可以在 N3936 中找到此文本,这是当前的 工作草案和N3937C++14 DIS.

在 C++1y 之前

有趣的是,在这个草案之前,不同于 C 一直对不确定值的用途有明确的定义 C++ 使用术语不确定值甚至没有定义它(假设我们不能从 C99 借用定义) 以及参见缺陷报告 616.我们不得不依赖 未指定的左值到右值转换,在 C++11 标准草案4.1左值到右值转换段落1中有介绍,它说:

<块引用>

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

<小时>

脚注:

  1. 1787缺陷报告 616,我们可以在 N3903

As covered in Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB? the C++ standard has a surprising example in section 3.3.2 Point of declaration in which an int is initialized with it's own indeterminate value:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

Which Johannes answer to this question indicates is undefined behavior since it requires an lvalue-to-rvalue conversion.

In the latest C++14 draft standard N3936 which can be found here this example has changed to:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

Has something changed in C++14 with respect to indeterminate values and undefined behavior that has driven this change in the example?

解决方案

Yes, this change was driven by changes in the language which makes it undefined behavior if an indeterminate value is produced by an evaluation but with some exceptions for unsigned narrow characters.

Defect report 1787 whose proposed text can be found in N39141 was recently accepted in 2014 and is incorporated in the latest working draft N3936:

The most interesting change with respect to indeterminate values would be to section 8.5 paragraph 12 which goes from:

If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ]

to (emphasis mine):

If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17 [expr.ass]). [Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2 [basic.start.init]. —end note] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

  • If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of:

    • the second or third operand of a conditional expression (5.16 [expr.cond]),

    • the right operand of a comma (5.18 [expr.comma]),

    • the operand of a cast or conversion to an unsigned narrow character type (4.7 [conv.integral], 5.2.3 [expr.type.conv], 5.2.9 [expr.static.cast], 5.4 [expr.cast]), or

    • a discarded-value expression (Clause 5 [expr]),

    then the result of the operation is an indeterminate value.

  • If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the right operand of a simple assignment operator (5.17 [expr.ass]) whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.

  • If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.

and included the following example:

[ Example:

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
}

end example ]

We can find this text in N3936 which is the current working draft and N3937 is the C++14 DIS.

Prior to C++1y

It is interesting to note that prior to this draft unlike C which has always had a well specified notion of what uses of indeterminate values were undefined C++ used the term indeterminate value without even defining it (assuming we can not borrow definition from C99) and also see defect report 616. We had to rely on the underspecified lvalue-to-rvalue conversion which in draft C++11 standard is covered in section 4.1 Lvalue-to-rvalue conversion paragraph 1 which says:

[...]if the object is uninitialized, a program that necessitates this conversion has undefined behavior.[...]


Footnotes:

  1. 1787 is a revision of defect report 616, we can find that information in N3903

这篇关于C++ 标准是否在 C++14 中关于不确定值和未定义行为的使用发生了变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆