C++默认初始化和值初始化:它们有何区别,什么时候调用它们以及如何可靠地初始化模板类型成员。

41
我的问题与这个和其他几个类似的问题有些重叠。它们有一些很好的答案,但我已经阅读了它们,仍然感到困惑,请不要认为这个问题是重复的。
因此,我有以下代码:
class A {
    public: int _a;
}

void main()
{
    A inst1;
    A* inst2 = new A;
    A* inst3 = new A();
}

inst1inst2中的_a未被初始化,而在inst3中被初始化为0。哪个初始化被调用了,为什么代码会按照这种方式工作?请注意我手头没有C++ 03标准,但我有最新的C++ 11草案(尽管我正在按照'03标准编程),因此引用'03标准或参考'11是非常受欢迎的。

P.S. 此研究背后的原始任务是正确地将任意模板类型T的成员零初始化。


可能是Value-initializing an automatic object?的重复问题。 - Ben Voigt
为即将到来的用户,还请查看以下链接:https://dev59.com/JG025IYBdhLWcg3wZlHd - Abhishek Mane
2个回答

48

不是很难:

A x;
A * p = new A;

这两个是默认初始化。因为您没有用户定义的构造函数,这意味着所有成员都进行了默认初始化。对于类似int的基本类型进行默认初始化意味着“没有初始化”。
接下来:
A * p = new A();

这是值初始化。 (我认为在C++98/03中不存在自动版本,尽管在C++11中您可以说A x {};,并且这个花括号初始化变成了值初始化。此外,A x = A();在实践中足够接近,尽管它是复制初始化,或者A x((A()))尽管是直接初始化。)

同样,在您的情况下,这意味着所有成员都将进行值初始化。对于基本类型的值初始化意味着零初始化,这反过来意味着变量被初始化为零(所有基本类型都有)。

对于类类型的对象,默认初始化和值初始化都会调用默认构造函数。然后发生的情况取决于默认构造函数是编译器定义还是用户定义。如果是用户定义的,则在默认初始化和值初始化中表现出相同的方式,并且发生的情况取决于构造函数的初始化列表,游戏会递归地继续进行成员变量。如果是编译器定义的,则默认初始化和值初始化的行为与预期相同。


@VioletGiraffe:希望不是这样。不要混淆“初始化”(一种语法概念)和“构造”(对象模型的一部分)。前者有时会导致后者,但这里存在一些重叠和令人困惑的术语。 - Kerrek SB
@K-ballo:绝对不是。请自行尝试并哭泣吧 :-) - Kerrek SB
1
@Kerrek SB:也许是 A x((A())); 吧?否则还是复制初始化,不是吗? - K-ballo
@Kerrek SB:好的,现在我完全迷失了,我不明白多出来一对括号有什么区别。哦,我懂得了复制初始化,忽略我之前的问题。我必须承认,我没有注意到=,它会调用一个复制构造函数。 - Violet Giraffe
1
@VioletGiraffe: 因为 A x(A()) 声明了 x 作为一个返回值为 A,并且传入一个不带参数的函数(或指向不带参数函数的指针)的函数。这不是你原来想要声明的 :-) - Kerrek SB
显示剩余12条评论

1

是的,A inst4(); 被视为函数声明。std::string str(); 应该是一样的(即我认为你错误地认为它可以工作)。

显然(来自这里),C++03 将使 inst3._a 为 0,但 C++98 则会将其保持未初始化状态。


你说得对,它们都是函数声明,我没有注意到警告。我以为应该是一个错误。 - Violet Giraffe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接