请考虑这段代码:

#include <iostream>

int main()
{
    struct A
    {
        int x;
        int y;
        int z;

        int foo()
        {
            std::cout << "enter foo: " << this->x << "," << this->y << "," << this->z << std::endl;
            return 5;
        }

        int moo()
        {
            std::cout << "enter moo: " << this->x << "," << this->y << "," << this->z << std::endl;
            this->x = 1;
            this->z = 10;
            return 2;
        }
    };

    A b { b.foo(), b.z = b.moo(), 3};

    std::cout << "final: " << b.x << "," << b.y << "," << b.z << std::endl;

    return 0;
}

我的 VS2017(x64 版本)中的结果:
enter foo: 0,0,0
enter moo: 5,0,0
final: 1,2,3

ideone.com (gcc 6.3) https://ideone.com/OGqvjW 的结果:
enter foo: 0,0,3
enter moo: 5,0,3
final: 1,2,2

一个编译器在所有事情之前立即将 z 成员设置为 3,然后在调用方法和赋值时覆盖它,另一个编译器在所有事情的最后这样做。

问:对这种行为的解释是什么?

谢谢你。

最佳答案

是的,这是未定义的行为:

int foo()
{
    std::cout << "enter foo: " << this->x << "," << this->y << "," << this->z << std::endl;
    //                            ~~~~~~~           ~~~~~~~           ~~~~~~~
}

在调用 foo() 时, xyz 尚未初始化。来自 [dcl.init]/12 :



其余情况均不适用。因此打印 xyz 存在未定义的行为。无异于:
int x;
std::cout << x; // ub

我之前的回答是肯定的,但出于一生的原因。它已经表明 A b{ b.foo(), b.z = b.moo(), 3}; 中的初始化是非空的,因此在初始化结束之前对 b 的任何成员的任何访问都是 UB。但是,xskxzr 已经向我表明,为了使初始化非空,您 must have constructors invokedint 没有构造函数。这使得 b 的初始化变得空洞。这对我来说在概念上似乎很奇怪,但这方面的措辞很清楚。

关于c++ - 这是未定义的行为还是 struct init 的错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48035195/

10-16 00:27