【问题标题】:Why is this simple assignment undefined behaviour?为什么这个简单的赋值是未定义的行为?
【发布时间】:2012-02-06 16:33:31
【问题描述】:

我正在刷新我对值初始化与默认初始化的理解,并遇到了this

struct C {
    int x;
    int y;
    C () { }
};

int main () {
    C c = C ();
}

显然这是 UB 因为

在 C() 的情况下,有一个构造函数能够 初始化 x 和 y 成员,因此不会进行初始化。 因此,尝试将 C() 复制到 c 会导致未定义的行为。

我想我明白为什么,但我不确定。有人可以详细说明吗?

也就是说这也是UB?

int x; x = x;

顺便说一句,关于值初始化,以下是否保证为零?

int x = int ();

【问题讨论】:

  • 不确定你的意思。如果您的意思是 x 和 y 的值将未初始化,那么是的,但是您已经回答了自己的问题(因为构造函数没有这样做)。至于C c=C();我认为这是完全正确的。
  • @Sid: 不,使用未初始化对象的值会产生未定义的行为。
  • @MikeSeymour 我认为 OP 明白这一点,但想知道语句 C c = C();本身就是UB。它在语法和语义上都是正确的。当然 x 和 y 将被初始化,因为构造函数没有做任何事情 - 所以这当然不是好的编程习惯。
  • @Sid:我不同意你关于C c = C(); 有效的说法。 C() 成员的未初始化值用于初始化 c,使用这些值会产生未定义的行为;因此它是无效的。
  • @Sid: 那么关键的观察就是如果没有发生复制省略,那么C c = C();“使用”成员xy创建的临时成员的未初始化值C()。所以它是UB。

标签: c++ undefined-behavior value-initialization


【解决方案1】:

您的第一个示例具有未定义的行为,因为默认的编译器 生成的复制构造函数将进行成员复制,ints 可能有 陷印值,并读取陷印值来复制它可能会导致 程序崩溃。

在实践中,我无法想象这真的会崩溃;编译器 几乎肯定会优化副本,即使没有,它 可能会使用一些特殊的按位复制,无需复制 检查陷印值。 (在 C++ 中,您可以保证能够 复制字节。)

对于第二种情况,同样是未定义的行为。虽然在这种情况下, 你有赋值而不是复制构造,编译器是 不太可能优化它。 (你的第一个任务没有 例如,仅复制构造。)

第三个,是的。带有空括号的初始化程序(并且没有 用户定义的默认初始化程序来覆盖它)首先执行零 初始化(与具有静态生命周期的变量完全相同)。

【讨论】:

  • +1,一些调试工具在虚拟机中运行应用程序,它会捕获(在某些情况下)将其识别为潜在问题。但我同意,在实际情况下,您可能只是复制未初始化的内存并移动它。
  • 在 C++14 中,引用是 [dcl.init]/12 "] 如果评估产生不确定值,则行为未定义,但以下情况除外:" - 无情况涵盖此代码
【解决方案2】:

我不认为这实际上是undefined behavior,尽管c 中的值有unspecified values。也就是说,只要您最终不使用这些未指定的值,程序的行为就会得到很好的定义。如果您使用它们,例如在一个条件或打印它们,结果没有定义。但是,我不认为该程序可以做任何奇怪的事情。

关于在内置类型上使用默认构造函数,这保证产生类型的零值,即0 用于整数,0.0 用于浮点类型等。这也扩展到没有构造函数的类型。一旦有任何构造函数,您需要自己负责在没有构造函数的情况下构造成员。

【讨论】:

  • 哦,你和詹姆斯·坎泽的直接枪战!他说复制构造函数“使用”未初始化的值,这样做就是 UB。你说的不一样。
  • @SteveJessop 但这个答案似乎更正确,不是吗? :) , +1
  • @Mr.Anubis:在最高级别上似乎存在分歧,您可以在 C++ 中使用未初始化的值做什么。标准中有一些文本说您不能执行左值-右值转换,但人们会认为(与其他对象表示一样)您可以将其作为unsigned char 访问。在实践中,生成的复制 ctor 除了盲目复制数据之外不太可能做任何事情,但为了安全起见,我相信 James 对标准允许的内容是正确的。例如,如果int 有任何校验位,则复制可能会附带检查奇偶校验位,如果错误则使用 UB。
  • @SteveJessop 啊,明白了。谢谢
【解决方案3】:

没有。将会发生的是大多数编译器会优化变量 out 的设置,但那些不这样做的编译器根本不会改变 x 的值。和下面的代码一样:

int x = 0;
x = 0;

不是第二行不执行,而是什么都不做。

【讨论】:

  • 重点是,如果我发布的 sn-ps 是 UB,那么编译器优化可能会导致 any 结果。
  • 我不同意,从技术上讲,从未设置的值读取是未定义的行为。编译器是否优化读取是未定义行为的可能结果的之一
猜你喜欢
  • 2013-09-13
  • 2011-05-05
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 2019-12-26
相关资源
最近更新 更多