这是未定义的行为还是 struct init 的错误?
Is this undefined behaviour or a bug with struct init?
请考虑这段代码:
#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()
时,x
、y
和z
尚未初始化。来自 [dcl.init]/12:
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 ([expr.ass]). [...] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases: [...]
None 的剩余情况适用。因此打印 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
的初始化变得空洞。这在我看来在概念上很奇怪,但是这方面的措辞很清楚。
请考虑这段代码:
#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()
时,x
、y
和z
尚未初始化。来自 [dcl.init]/12:
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 ([expr.ass]). [...] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases: [...]
None 的剩余情况适用。因此打印 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
的初始化变得空洞。这在我看来在概念上很奇怪,但是这方面的措辞很清楚。