Gab*_*iel 81 c++ c++11 c++03 c++98 c++14
我对value-&default-&zero-initialization非常困惑.特别是当他们参与不同的标准C++ 03和C++ 11(和C++ 14)时.
我引用并试图在这里扩展一个非常好的答案Value-/Default-/Zero-初始化C++ 98和C++ 03,以使其更加通用,因为它可以帮助很多用户,如果有人可以帮助填写需要差距,以便对何时发生的情况有一个很好的概述?
通过示例的全面见解简而言之:
有时新运算符返回的内存将被初始化,有时它不会取决于您正在新建的类型是POD(普通旧数据),还是它是一个包含POD成员且正在使用的类编译器生成的默认构造函数.
假设:
struct A { int m; };
struct B { ~B(); int m; };
struct C { C() : m(){}; ~C(); int m; };
struct D { D(){}; int m; };
struct E { E() = default; int m;} /** only possible in c++11/14 */
struct F {F(); int m;} F::F() = default; /** only possible in c++11/14 */
Run Code Online (Sandbox Code Playgroud)
在C++ 98编译器中,应该发生以下情况:
new A - 不确定值(A是POD)new A()- 零初始化 new B - 默认构造(B::m未初始化,B非POD)new B()- 默认构造(B::m未初始化)new C - 默认构造(C::m零初始化,C非POD)new C()- 默认构造(C::m零初始化)new D - 默认构造(D::m未初始化,D非POD)new D()- 默认构造?(D::m未初始化)在符合C++ 03的编译器中,事情应该像这样工作:
new A - 不确定值(A是POD)new A() - value-initialize A,这是零初始化,因为它是POD.new B - default-initializes(B::m保留未初始化,B非POD)new B() - value-initializes B对所有字段进行零初始化,因为它的默认ctor是编译器生成的而不是用户定义的.new C - default-initializes C,调用默认的ctor.(C::m零初始化,C非POD)new C() - value-initializes C,调用默认的ctor.(C::m零初始化)new D - 默认构造(D::m未初始化,D非POD)new D() - 值初始化D?,调用默认的ctor(D::m未初始化)斜体值和?是不确定的,请帮助纠正这个:-)
在符合C++ 11的编译器中,事情应该如下:
??? (如果我从这里开始请帮忙,无论如何都会出错)
在符合C++ 14的编译器中,事情应该像这样工作: ??? (请帮助,如果我从这里开始它将会出错) (根据答案草案)
new A - default-initializes A,编译器gen.ctor,(leavs A::muninitialized)(A是POD)new A() - value-initializes A,这是从[dcl.init]/8中的 2. point开始的零初始化
new B - default-initializes B,编译器gen.ctor,(leavs B::muninitialized)(B非POD)
new B() - value-initializes B对所有字段进行零初始化,因为它的默认ctor是编译器生成的而不是用户定义的.new C - default-initializes C,调用默认的ctor.(C::m零初始化,C非POD)new C() - value-initializes C,调用默认的ctor.(C::m零初始化)new D - default-initializes D(D::m未初始化,D非POD)new D() - value-initializes D,调用默认的ctor(D::m未初始化)new E - default-initializes E,调用comp.根.构造函数.(E::m未初始化,E是非POD)new E() -值初始化E,其零初始化E自2点在[dcl.init]/8)new F - default-initializes F,调用comp.根.构造函数.(F::m未初始化,F非POD)new F() - value-initializes F,默认初始化为 F 1.指向[dcl.init]/8(Fctor函数是用户提供的,如果它是用户声明的,并且在第一次声明时未明确默认或删除.链接)Col*_*mbo 24
C++ 14指定用new[expr.new]/17(C++ 11中的[expr.new]/15)创建的对象的初始化,并且该注释不是注释,而是当时的规范文本):
甲新表达式创建类型的对象
T如下初始化该对象:
- 如果省略new-initializer,则默认初始化对象(8.5).[ 注意:如果未执行初始化,则对象具有不确定的值.- 结束说明 ]
- 否则,根据8.5的初始化规则解释new-initializer以进行直接初始化.
默认初始化在[dcl.init]/7中定义(在C++ 11中为/ 6,并且措辞本身具有相同的效果):
到默认初始化的类型的对象
T是指:
- 如果
T是一个(可能是cv限定的)类类型(第9节),T则调用默认构造函数(12.1)(如果T没有默认构造函数或重载解析(13.3),则初始化是错误的,导致歧义或在从初始化的上下文中删除或无法访问的函数);- 如果
T是数组类型,则每个元素都是默认初始化的 ;- 否则,不执行初始化.
从而
new A只会导致A调用默认构造函数,它不会初始化m.不确定的价值.应该是相同的new B.new A() 根据[dcl.init]/11(C++ 11中的/ 10)解释:
初始化器为空的括号集的对象,即
(),应进行值初始化.
现在考虑[dcl.init]/8(C++ 11†中的/ 7):
对值初始化类型的对象
T意味着:
- if
T是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;- 如果
T是没有用户提供或删除的默认构造函数的(可能是cv限定的)类类型,则对象将进行零初始化并检查默认初始化的语义约束,如果T具有非平凡的默认构造函数,该对象是默认初始化的;- 如果
T是数组类型,则每个元素都是值初始化的;- 否则,该对象被零初始化.
因此new A()将零初始化m.这对于A和B.
new C并且new C()将再次默认初始化对象,因为最后一个引用的第一个项目符号点适用(C具有用户提供的默认构造函数!).但是,显然,现在m在两种情况下都在构造函数中初始化.
†好吧,这一段在C++ 11中的措辞略有不同,不会改变结果:
对值初始化类型的对象
T意味着:
- 如果
T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则T调用默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);- 如果
T是没有用户提供的构造函数的(可能是cv限定的)非联合类类型,则该对象是零初始化的,如果T隐式声明的默认构造函数是非平凡的,则调用该构造函数.- 如果
T是数组类型,则每个元素都是值初始化的;- 否则,该对象被零初始化.
Abh*_*jit 12
以下答案扩展了答案/sf/answers/43428171/,它将作为C++ 98和C++ 03的参考
引用答案
C++ 11(参考n3242)
8.5 Initializers [dcl.init]指定变量POD或非POD可以初始化为brace-or-equal-initializer,它可以是 braced-init-list或initializer-clause,统称为 brace-or-equal-初始化器或使用(表达式列表).在C++ 11之前,只支持(expression-list)或initializer-clause,尽管initializer-clause比C++ 11中的更受限制.在C++ 11中,initializer-clause现在支持除了C++ 03中的赋值表达式之外的braced-init-list.以下语法总结了新支持的子句,其中部分为粗体是在C++ 11标准中新添加的.
initializer:
brace-or-equal-initializer
(expression-list)
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
initializer-list:
initializer-clause ... opt
initializer-list,initializer-clause ... opt**
braced-init-list:
{initializer-list,opt}
{}
与C++ 03一样,C++ 11仍支持三种初始化形式
注意
在C++ 11中添加了以粗体突出显示的部分,并且从C++ 11中删除了被删除的部分.
在以下情况下执行
零初始化T类型的对象或引用意味着:
- 如果T是标量类型(3.9),则将对象设置为值0(零),作为整数常量表达式,转换为T;
- 如果T是(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的,并且填充初始化为零位;
- 如果T是(可能是cv限定的)联合类型,则对象的第一个非静态命名数据成员初始化为零,并且填充初始化为零位;
- 如果T是数组类型,则每个元素都是零初始化的;
- 如果T是引用类型,则不执行初始化.
在以下情况下执行
默认初始化T类型的对象意味着:
- 如果T是(可能是cv限定的)
非POD类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);- 如果T是数组类型,则每个元素都是默认初始化的;
- 否则,不执行初始化.
注意在C++ 11之前,当没有使用初始化程序时,只有具有自动存储持续时间的非POD类类型被认为是默认初始化的.
对值类型T的对象进行值初始化意味着:
- 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的) ;
- 如果T是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,
那么T的每个非静态数据成员和基类组件都是值初始化的;那么该对象是零初始化的,如果T的隐式声明的默认构造函数是非平凡的,则调用该构造函数.- 如果T是数组类型,那么每个元素都是值初始化的;
- 否则,该对象被零初始化.
总结一下
注意标准中的相关引用以粗体突出显示
| 归档时间: |
|
| 查看次数: |
11708 次 |
| 最近记录: |