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

时间:2014-02-21 17:10:57

标签: c++ language-lawyer c++03

当我在讨论我的另一个问题时,我实际上已经了解了这个问题(Member not zeroed, a clang++ bug?)。那个问题是关于C ++ 11的值初始化,但当我看到有人在那里发布的C ++ 03值初始化规则时,我很困惑。

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

  

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

     
      
  • 如果T是具有用户声明的构造函数(12.1)的类类型(第9节),则调用T的默认构造函数(并且   如果T没有可访问的默认值,则初始化是错误的   构造函数);
  •   
  • 如果T是没有用户声明的构造函数的非联合类类型,那么T的每个非静态数据成员和基类组件都是   值初始化;
  •   
  • 如果T是数组类型,则每个元素都是值初始化的;
  •   
  • 否则,对象为零初始化
  •   

请查看第二个项目符号,它定义了没有用户声明的构造函数的类型的value-initialize过程。此规则未提及构造函数调用。正如我们从其他值初始化的描述或默认初始化的描述中可以看到的那样,如果应该调用构造函数,它将在标准的文本中明确提到。我知道有一些初始化形式,构造函数不会被调用(例如{} - 初始化聚合),但是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为例。我的观点是,不会跳过对非平凡构造函数的调用导致对象有效性的一些潜在问题吗?毕竟,出于某种原因,它被称为非平凡的。

2 个答案:

答案 0 :(得分:0)

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

相反,vtable是编译器必须遵循的其他规则的结果,与虚函数绑定等有关。因此,无论是否调用构造函数,vtable都将设置为某处,否则编译器将无法满足其他义务。这与价值初始化规则并不矛盾;相反,它增加了实施规则的实用性。

答案 1 :(得分:0)

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

因此,这实际上比您引用的值初始化“更少” - 因为该值初始化值 - 初始化所有数据成员和基类子对象。所以它完成所有构造函数,以及更多。

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