请考虑这段代码:
#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,然后在调用方法和赋值时将其覆盖,另一个在最后,在所有内容之后执行。
问。对这种行为有什么解释?
谢谢。
答案 0 :(得分:7)
是的,这是未定义的行为:
int foo()
{
std::cout << "enter foo: " << this->x << "," << this->y << "," << this->z << std::endl;
// ~~~~~~~ ~~~~~~~ ~~~~~~~
}
在调用foo()
时,x
,y
和z
尚未初始化。来自[dcl.init]/12:
如果没有为对象指定初始值设定项,则默认初始化该对象。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换为止( [expr.ass])。 [...]如果评估产生了不确定的值,则行为是不确定的,除非在下列情况下:[...]
其余案件均不适用。因此,打印x
,y
和z
会有未定义的行为。与众不同:
int x;
std::cout << x; // ub
我之前的回答是肯定的,但是出于终生的原因。它曾建议A b{ b.foo(), b.z = b.moo(), 3};
中的初始化是非空的,因此在初始化结束之前b
的任何成员的任何访问都是UB。但是,xskxzr后来告诉我,为了使初始化非空,你must have constructors invoked和int
没有构造函数。这使b
的初始化成为空白。这在概念上对我来说很奇怪,但这方面的措辞很清楚。