以下短语在 C++ 中是什么意思:零初始化、默认值初始化和值初始化?

What do the following phrases mean in C++: zero-, default- and value-initialization?

提问人:Bill 提问时间:10/23/2009 最后编辑:DestructorBill 更新时间:7/14/2019 访问量:37023

问:

以下短语在 C++ 中是什么意思:

  • 零初始化,

  • default-initialization,以及

  • 值初始化

C++ 开发人员应该了解它们吗?

C 初始化 C++-FAQ

评论

1赞 Steve Jessop 12/8/2010
这与 stackoverflow.com/questions/620137/ 有关(但不完全相同)......
26赞 legends2k 5/7/2013
还有更多!初始化的完整列表:值、直接、复制、列表(C++11 新介绍)、聚合、引用、零、常量和默认值;en.cppreference.com/w/cpp/language/initialization 列出了所有这些示例:)
0赞 ZoomIn 8/23/2022
@legends2k 这很好,谢谢!我希望有人能谈论更新的标准!

答:

91赞 Kirill V. Lyadvinsky 10/23/2009 #1

C++03 标准 8.5/5:

对 T 类型的对象进行零初始化意味着:
— 如果 T 是标量类型 (3.9),则将对象设置为值 0(零)转换为 T;
— 如果 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 非限定版本用于零初始化、默认初始化和值初始化的这些定义。

评论

24赞 Alexei Sholik 7/9/2013
对于 C++11,这可能已过时。cppreference.com 指出,默认初始化不会对成员进行零初始化(只有值初始化会)。
5赞 Adrian McCarthy 3/7/2014
@android提出了一个重要的观点,我在其他地方没有看到答案,所以我提出了一个新问题。stackoverflow.com/questions/22233148/......
67赞 Michael Burr 10/23/2009 #2

需要意识到的一件事是,“值初始化”是 C++ 2003 标准的新内容——它在最初的 1998 标准中不存在(我认为这可能是唯一的区别,而不仅仅是澄清)。参见 Kirill V. Lyadvinsky 的答案,了解直接来自标准的定义。

有关这些类型的初始化的不同行为以及它们何时启动(以及它们从 c++98 到 C++03 的不同时间)的详细信息,请参阅之前关于行为的答案:operator new

答案的要点是:

有时,new 运算符返回的内存将被初始化,有时则不会初始化,具体取决于您要更新的类型是 POD,还是包含 POD 成员的类并使用编译器生成的默认构造函数。

  • 在 C++1998 中,有两种类型的初始化:零初始化和默认初始化
  • 在 C++2003 中,添加了第三种初始化类型,即值初始化。

至少可以说,它相当复杂,当不同的方法发挥作用时,它是微妙的。

需要注意的一件事是,即使在 VS 2008(VC 9 或 cl.exe 版本 15.x)中,MSVC 也遵循 C++98 规则。

以下代码片段显示 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;
}

评论

2赞 Johannes Schaub - litb 10/23/2009
这并不重要,而是在第三行值初始化 m。如果更改为 ,则很重要。:)intm()int m;B m;
0赞 Michael Burr 10/23/2009
对 - 并且不在此示例中使用(它们是从其他链接的答案继承而来的)。尽管 C++98 和 C++03 在描述构造方式和构造时使用不同的术语,但这两个标准的结果是相同的。只会导致不同的行为。ACACstruct B
1赞 Johannes Schaub - litb 9/27/2010
我的意思是,如果你把 C 改成 ,那么你将是 0。但是,如果它像您所说的那样默认初始化 C++03,那么就不会像在 C++98 中那样初始化。struct C { C() : m() {}; ~C(); B m; };m.mmm.m
1赞 Brent Bradburn 7/27/2011
有关此功能的 MSVC 处理的其他有趣评论:stackoverflow.com/questions/3931312/...
1赞 Jean 4/27/2018
Red Hat 4.4.7-18 的 g++ 4.4.7 20120313使用您的示例将 m 初始化为 0(使用 -std=c++98 编译)。