11

Why does

struct wrapper
{
    explicit wrapper(void *);
    wrapper() = default;
    int v;
};

int main() { return wrapper().v; }  // You should run this in Debug mode

return 0xCCCCCCCC, whereas

struct wrapper { wrapper() = default; int v; };
int main() { return wrapper().v; }

and

struct wrapper { int v; };
int main() { return wrapper().v; }

both return 0?

4

2 回答 2

4

value-initialization期间,如果T是没有用户提供或删除的默认构造函数的类类型,则该对象为零初始化(第 8.5/8.2 节)。确实如此wrapper

您的第一个示例匹配零初始化的第三种情况(§8.5/6.1,强调我的)

— 如果T是标量类型(3.9),则将对象初始化为通过将整型文字 0(零)转换为 获得的值T

如果T是(可能是 cv 限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都被初始化为零,并且填充被初始化为零位;

— 如果T是(可能是 cv 限定的)联合类型,则对象的第一个非静态命名数据成员初始化为零,填充初始化为零位;

— 如果 T 是数组类型,则每个元素都初始化为零

— 如果 T 是引用类型,则不执行初始化

所以在你的第一个例子中,v应该是零初始化的。这看起来像一个错误。

在您的第二个和第三个示例中,您不再有用户提供的构造函数,但是您确实有一个不是用户提供或删除的默认构造函数,因此您的示例仍然属于零初始化的第三种情况,即零初始化每个非静态数据成员。VS 在那里是正确的。

于 2014-12-24T23:49:00.357 回答
4

这似乎是 MSVC 中的一个错误。在所有三种情况下wrapper,都没有用户提供的默认构造函数,因此使用wrapper()调用进行初始化:

(来自n3690的所有引用)

(8.5/11) 初始化器为空括号集的对象,即 (),应进行值初始化。

(感谢 dyp),这将导致零初始化int v

初始化然后将我们引向规则:

(8.5/8) 如果 T 是(可能是 cv 限定的)类类型,没有用户提供或删除的默认构造函数,则该对象为零初始化,并检查默认初始化的语义约束。

零初始化规则状态:

(8.5/6) 如果 T 是(可能是 cv 限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都被初始化为零并且填充被初始化为零位

int v作为的数据成员wrapper是零初始化本身根据:

(8.5/6) 如果 T 是标量类型 (3.9),则将对象初始化为通过将整型文字 0(零)转换为 T 获得的值

这不是您观察到的行为。

于 2014-12-25T00:00:36.033 回答