以下短语在 C++ 中是啥意思:零初始化、默认初始化和值初始化?
Posted
技术标签:
【中文标题】以下短语在 C++ 中是啥意思:零初始化、默认初始化和值初始化?【英文标题】:What do the following phrases mean in C++: zero-, default- and value-initialization?以下短语在 C++ 中是什么意思:零初始化、默认初始化和值初始化? 【发布时间】:2010-12-09 11:04:21 【问题描述】:以下短语在 C++ 中的含义:
零初始化,
默认初始化,以及
值初始化
C++ 开发人员应该对它们了解多少?
【问题讨论】:
这与***.com/questions/620137/…相关(但不完全相同) 还有更多!初始化的完整列表:值、直接、复制、列表(C++11 新介绍)、聚合、引用、零、常量和默认值; en.cppreference.com/w/cpp/language/initialization 用例子列出了所有这些:) 【参考方案1】:C++03 标准 8.5/5:
零初始化 T 类型的对象意味着: — 如果 T 是标量类型(3.9),则将对象设置为转换为 T 的值 0(零); — 如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的; — 如果 T 是联合类型,则对象的第一个命名数据成员为零初始化; — 如果 T 是数组类型,则每个元素都初始化为零; — 如果 T 是引用类型,则不执行初始化。
默认初始化一个 T 类型的对象意味着: — 如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的); — 如果 T 是数组类型,则每个元素都是默认初始化的; — 否则,对象被零初始化。
值初始化一个 T 类型的对象意味着: — 如果 T 是具有用户声明的构造函数 (12.1) 的类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是错误的); — 如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都是值初始化的; — 如果 T 是数组类型,则每个元素都是值初始化的; — 否则,对象被零初始化
要求对引用类型的实体进行默认初始化或值初始化的程序是格式错误的。如果 T 是 cv 限定类型,则 T 的 cv 非限定版本用于零初始化、默认初始化和值初始化的这些定义。
【讨论】:
这对于 C++11 来说可能已经过时了。 cppreference.com 声明默认初始化不零初始化成员(只有值初始化)。 @android 提出了一个重要的观点,我在其他地方没有看到答案,所以我提出了一个新问题。 ***.com/questions/22233148/…【参考方案2】:需要意识到的是,“值初始化”是 C++ 2003 标准中的新内容——它在 1998 年的原始标准中不存在(我认为这可能是唯一的区别,不仅仅是澄清)。直接来自标准的定义见Kirill V. Lyadvinsky's answer。
有关这些类型初始化的不同行为以及它们何时启动(以及它们何时从 c++98 到 C++03 不同)的详细信息,请参阅关于 operator new
行为的先前答案:
答案的重点是:
有时 new 运算符返回的内存将被初始化,有时它不会取决于您要更新的类型是 POD,还是包含 POD 成员的类并且正在使用编译器 -生成的默认构造函数。
在 C++1998 中有 2 种类型的初始化:零和默认 在 C++2003 中,添加了第三种初始化类型,即值初始化。
至少可以说,这是相当复杂的,而且当不同的方法起作用时是微妙的。
需要注意的一点是 MSVC 遵循 C++98 规则,即使在 VS 2008(VC 9 或 cl.exe 版本 15.x)中也是如此。
以下 sn-p 显示 MSVC 和 Digital Mars 遵循 C++98 规则,而 GCC 3.4.5 和 Comeau 遵循 C++03 规则:
#include <cstdio>
#include <cstring>
#include <new>
struct A int m; ; // POD
struct B ~B(); int m; ; // non-POD, compiler generated default ctor
struct C C() : m() ; ~C(); int m; ; // non-POD, default-initialising m
int main()
char buf[sizeof(B)];
std::memset( buf, 0x5a, sizeof( buf));
// use placement new on the memset'ed buffer to make sure
// if we see a zero result it's due to an explicit
// value initialization
B* pB = new(buf) B(); //C++98 rules - pB->m is uninitialized
//C++03 rules - pB->m is set to 0
std::printf( "m is %d\n", pB->m);
return 0;
【讨论】:
这对int
无关紧要,但第三行值的m()
会初始化m。如果您将 int m;
更改为 B m;
,这很重要。 :)
对 - A
和 C
在此示例中未使用(它们是从其他链接的答案中继承而来的)。尽管 C++98 和 C++03 在描述 A
和 C
的构造方式时使用了不同的术语,但两种标准的结果是相同的。只有 struct B
会导致不同的行为。
我的意思是,如果你将 C 更改为 struct C C() : m() ; ~C(); B m; ;
,那么你将有 m.m
为 0。但如果它会像你说的 C++03 那样默认初始化 m
, 那么m.m
不会像在 C++98 中那样被初始化。
关于 MSVC 处理此功能的其他有趣的 cmets:***.com/questions/3931312/…
g++ 4.4.7 20120313 for Red Hat 4.4.7-18 使用您的示例将 m 初始化为 0(使用 -std=c++98 编译)。以上是关于以下短语在 C++ 中是啥意思:零初始化、默认初始化和值初始化?的主要内容,如果未能解决你的问题,请参考以下文章