当存在其他构造函数时,"ctor() = default"为什么会更改行为?
Why does "ctor() = default" change behavior when other constructors are present?
为什么
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
?
在值初始化期间,如果T
是没有用户提供或删除的默认构造函数的类类型,则该对象初始化为零 (§8.5/8.2)。wrapper
确实如此。
您的第一个示例与零初始化的第三种情况匹配(§8.5/6.1,强调我的)
— 如果
T
是标量类型 (3.9),则对象初始化为通过转换整数文本获得的值0
(零)到T
;— 如果
T
是(可能符合 CV 条件的)非联合类类型,则每个非静态数据成员和每个基类子对象初始化为零,填充初始化为零位;— 如果
T
是(可能符合 CV 条件的)联合类型,则对象的第一个非静态命名数据成员初始化为零,填充初始化为零位;— 如果 T 是数组类型,则每个元素都是零初始化的
— 如果 T 是引用类型,则不执行初始化
因此,在您的第一个示例中,v
应该是零初始化的。这看起来像一个错误。
在第二个和第三个示例中,您不再有用户提供的构造函数,但您确实有一个不是用户提供或删除的默认构造函数,因此您的示例仍属于零初始化的第三种情况,即零初始化每个非静态数据成员。VS 在那里是正确的。
这似乎是 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 获得的值
这不是你观察到的行为。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 在提升multi_index容器中,是否定义了"default index"?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- 为什么使用默认构造函数"{}"而不是"= default"存在性能变化?
- 为什么 "=default" 析构函数与隐式声明的析构函数不同?
- 为什么要显式声明类特殊函数为"default"
- 为什么我不能对具有成员初始值设定项列表的默认 ctor 使用 =default。
- 为什么我收到错误:"there is more than one default constructor"?
- 当存在其他构造函数时,"ctor() = default"为什么会更改行为?
- 为什么在虚拟继承中调用Default构造函数
- 为什么我们需要使用virtual ~A() = default;而不是c++ 11中的virtual ~A(){}
- 为什么switch总是运行default?(与休息;包括)
- "No appropriate default constructor available" --为什么还要调用默认构造函数?
- 为什么主模板必须有default = void
- 为什么 =default on 运算符 = 在有 const 成员时编译