为了账号安全,请及时绑定邮箱和手机立即绑定

C ++中是否有隐式默认构造函数?

C ++中是否有隐式默认构造函数?

C++
喵喔喔 2019-11-11 14:21:57
在我目前正在阅读的书中(C ++ Without Fear),它说,如果您没有为类声明默认的构造函数,则编译器会为您提供一个,该构造函数“将每个数据成员清零”。我已经对此进行了试验,但没有看到任何归零行为。我在Google上也找不到任何提及此内容的信息。这仅仅是特定编译器的错误还是怪癖?
查看完整描述

3 回答

?
繁华开满天机

TA贡献1816条经验 获得超4个赞

如果未定义构造函数,则编译器将为您定义默认构造函数。

执行此

默认构造函数是:

  • 默认构造基类(如果基类没有默认构造函数,则编译失败)

  • 默认按照声明的顺序构造每个成员变量。(如果成员没有默认构造函数,则这是编译失败)。

注意:
POD数据(int,float,pointer等)没有显式构造函数,但是默认操作是不做任何事情(在C ++哲学的风向标中;除非明确要求,否则我们不愿为之付费)它)。

如果未定义析构函数/复制构造函数/赋值运算符,则编译器将为您构建其中的一个(因此,类始终具有析构函数/复制构造函数/赋值运算符(除非您作弊并明确声明一个但不定义它))。
默认实现为:

析构函数:

  • 如果定义了用户定义的析构函数,请执行提供的代码。

  • 以声明的相反顺序调用每个成员的析构函数

  • 调用基类的析构函数。

复制构造函数:

  • 调用基类Copy构造函数。

  • 按声明顺序为每个成员变量调用复制构造函数。

分配运算符:

  • 调用基类的赋值运算符

  • 按声明的顺序调用每个成员变量的赋值运算符。

  • 返回对此的引用。

注意POD数据的复制构造/分配运算符只是复制数据(因此,与RAW指针相关的浅表复制问题)。


查看完整回答
反对 回复 2019-11-11
?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

编译器会自动生成默认构造函数吗?

隐式生成的默认构造函数是否执行零初始化?

如果您从法律上解析2003年标准的语言,则答案是肯定的,否。但是,这还不是全部,因为与用户定义的默认构造函数不同,从头创建对象时并不总是使用隐式定义的默认构造函数 -还有其他两种情况:无构造和成员明智的值初始化。


“无构造”的情况实际上只是一种技术问题,因为它在功能上与调用琐碎的默认构造函数没有什么不同。另一种情况是更加有趣:成员明智值初始化通过使用调用“()” [仿佛明确调用一个没有参数的构造函数]和它绕过什么技术上称为的默认构造函数。相反,它对每个数据成员递归执行值初始化,对于原始数据类型,最终将解析为零初始化。


因此,实际上,编译器提供了两个不同的隐式定义的默认构造函数。其中一个确实对原始成员数据执行零初始化,而另一个则不执行。以下是一些示例,说明了如何调用每种类型的构造函数:


    MyClass a; // default-construction or no construction

    MyClass b = MyClass(); // member-wise value-initialization


    new MyClass; // default-construction or no construction

    new MyClass(); // member-wise value-initialization

注意:如果确实存在用户声明的默认构造函数,则按成员值初始化将简单地调用它并停止。


这是标准对此的详细说明...


如果不声明构造函数,则编译器会隐式创建一个默认构造函数[12.1-5]


默认构造函数不初始化基本类型[12.1-7]


MyClass() {} // implicitly defined constructor

如果使用“()”初始化对象,则不会直接调用默认构造函数。相反,它会引发很长的规则序列,称为值初始化 [8.5-7]


值初始化的最终效果是,永远不会调用隐式声明的默认构造函数。相反,将调用递归的按成员值初始化,最终将对所有原始成员进行零初始化,并在具有用户声明的构造函数的任何成员上调用默认构造函数[8.5-5]


值初始化甚至适用于原始类型-它们将被零初始化。[8.5-5]


a = int(); // equivalent to int a=0;

对于大多数目的来说,所有这些实际上都是没有实际意义的。类的编写者通常不能假定数据成员在隐式初始化序列中将被清零-因此,如果任何自管理类具有需要初始化的原始数据成员,则它应该定义自己的构造函数。


那么什么时候重要呢?


在某些情况下,通用代码可能要强制初始化未知类型。值初始化提供了一种方法。请记住,如果用户提供了构造函数,则不会发生隐式零初始化。


默认情况下,std :: vector包含的数据是值初始化的。这可以防止内存调试器识别与其他情况下未初始化的内存缓冲区相关的逻辑错误。


vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"

可以使用值初始化语法对原始类型或“普通数据”(POD)类型结构的整个数组进行零初始化。


new int[100]();

这篇文章提供了有关标准版本之间变化的更多详细信息,并且还指出了在主要编译器中以不同方式应用标准的情况。


查看完整回答
反对 回复 2019-11-11
?
月关宝盒

TA贡献1772条经验 获得超5个赞

C ++会生成一个默认的构造函数,但前提是您不提供自己的构造函数。该标准并没有说明将数据成员清零。默认情况下,当您第一次构造任何对象时,它们是未定义的。


这可能会造成混淆,因为大多数C ++基本类型确实具有默认的“构造函数”,这些默认构造函数会将它们初始化为零(int(),bool(),double(),long()等),但是编译器不会调用他们像对象对象一样初始化POD成员。


值得注意的是,STL 确实使用这些构造函数来默认构造保存原始类型的容器的内容。


查看完整回答
反对 回复 2019-11-11
  • 3 回答
  • 0 关注
  • 522 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信