C++03 中的某些值初始化情况不调用构造函数?

Certain case of value-initialization in C++03 doesn't call constructor?

本文关键字:情况 调用 构造函数 初始化 C++03      更新时间:2023-10-16

实际上,我是在讨论我的另一个问题时想到这个问题的(成员未归零,一个clang++错误?)。这个问题是关于C++11值初始化的,但当我看到有人在那里发布的C++03值初始化规则时,我很困惑。

C++03中的值初始化规则是:

值初始化T类型的对象意味着:

  • 如果T是一个具有用户声明构造函数(12.1)的类类型(子句9),则调用T的默认构造函数(并且如果T没有可访问的默认值,则初始化格式不正确构造函数)
  • 如果T是没有用户声明构造函数的非并集类类型,则T的每个非静态数据成员和基类组件都是值已初始化
  • 如果T是数组类型,则每个元素都被值初始化
  • 否则,对象初始化为零

请看第二个项目符号,它为没有用户声明构造函数的类型定义了值初始化过程。这个规则没有提到构造函数调用。正如我们从值初始化的其他情况的描述或默认初始化的描述中看到的那样,如果应该调用构造函数,它将在标准的文本中明确提及。我知道有某种初始化形式的构造函数不会被调用(例如聚合的{}-初始化),但non-union class type without a user-declared constructor的值初始化应该是这种情况吗?这种类型的隐式声明构造函数可以很容易地实现。例如:

class A {
public:
virtual void f() {}
};

根据C++03中的规则,如果在A对象的值初始化过程中没有调用隐式声明的非平凡构造函数,那么该对象的vptr是如何设置的?(我知道与vptr相关的东西都是由实现定义的,但这并没有改变我在这里试图表达的主要观点。)

(有人会说,规则中没有提到构造函数调用并不意味着构造函数不会被调用。好吧。假设构造函数会根据我可能忽略的其他规则被调用,但由于所有成员都需要进行值初始化,这不会导致成员的构造函数被调用不止一次吗?)

当C++03已经是C++11的时候,问一个问题可能看起来毫无价值。是的,这是一个有效的观点。然而,我认为如果我最终弄清楚这一点(我是否错了,为什么错了),我或多或少可以学到一些东西。

编辑:也许我不应该用vptr作为例子。我的观点是,跳过对非平凡构造函数的调用不会对对象的有效性造成一些潜在的问题吗?毕竟,它被称为非琐碎是有原因的。

就标准而言,构造函数不负责设置vtable。设立vtable没有任何责任;就标准而言,vtables并不存在。

相反,vtable是编译器必须遵循的其他规则的结果,这些规则与虚拟函数绑定等有关。因此,无论是否调用构造函数,vtable都将在的某个地方设置,因为否则编译器将难以履行其其他义务。这与值初始化规则并不矛盾;相反,它为实施该规则的实际操作增加了细微差别。

当类X没有用户提供的构造函数时,其默认构造函数的作用与X::X() {}形式的构造函数(C++03[class.ctor]§6)完全相同。就标准而言,这被定义为执行所有成员和基类子对象的默认初始化,,而不是其他因此,"调用生成的默认构造函数"与"默认初始化所有数据成员和基类子对象"相同

所以这实际上比你引用的值初始化做得"少"——因为值初始化值初始化所有数据成员和基类子对象。所以它完成了构造函数所做的一切,甚至更多。

就特定于实现的东西(如vtable指针)而言,这些都超出了标准的范围。编译器有责任确保其所有特定于实现的机制都能工作,而不考虑标准强制的构造函数调用。

相关文章: