为什么“ctor()= default”会在其他构造函数出现时改变行为?

时间:2014-12-24 22:59:15

标签: c++ visual-c++ constructor default-constructor visual-c++-2013

为什么

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

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

返回0xCCCCCCCC,而

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

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

都返回0

2 个答案:

答案 0 :(得分:4)

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

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

  
    

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

         

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

         

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

         

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

         

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

  

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

在你的第二个和第三个例子中,你不再拥有一个用户提供的构造函数,但你确实有一个非用户提供或删除的默认构造函数,所以你的例子仍然属于第三种情况,用于零初始化,这是对每个非静态数据成员进行零初始化。 VS在那里是正确的。

答案 1 :(得分: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

获得的值

这不是您观察到的行为。