未构造对象的调用方法:合法吗?

时间:2019-04-16 02:15:40

标签: c++ c++11

如果为对象预留了内存(例如,通过联合),但尚未调用构造函数,则调用该对象的非静态方法之一是合法的,前提是该方法不依赖于值任何成员变量?

我研究了一下,发现了一些有关“变体成员”的信息,但找不到与该示例有关的信息。

class D {
 public:
  D() { printf("D constructor!\n"); }
  int a = 123;
  void print () const {
    printf("Pointer: %p\n", &a);
  };
};

class C {
 public:
  C() {};
  union {
    D memory;
  };
};

int main() {
  C c;
  c.memory.print();
} 

在此示例中,我在不调用构造函数的情况下调用了print()。目的是稍后调用构造函数,但即使在调用构造函数之前,我们也知道变量 a 将驻留在何处。显然,此时 a 的值尚未初始化,但是print()并不关心该值。

这对于c ++ 11使用gcc和clang编译时似乎可以按预期工作。但是我想知道我是否在这里调用某些非法或未定义的行为。

1 个答案:

答案 0 :(得分:6)

我认为这是未定义的行为。您的变量成员C::memory尚未初始化,因为C的构造函数未提供初始化程序[class.base.init]/9.2。因此,c.memory的生命周期尚未在您调用方法print() [basic.life]/1时开始。基于[basic.life]/7.2

  

类似地,在对象的生存期开始之前但已分配了该对象将要占用的存储空间之后,或者,在对象的生存期结束之后且该对象占用的存储空间之前如果重新使用或释放​​它,则可以使用引用原始对象的任何glvalue,但只能以有限的方式使用。 […] 如果该程序具有未定义的行为,

     
      
  • […]
  •   
  • glvalue用于调用对象的非静态成员函数,或
  •   
  • […]
  •   

强调我的

注意:我指的是上面的current C++ standard draft,但是,有关C ++ 11的措辞基本上是相同的,除了在C ++ 11中,D具有非简单的初始化至关重要,因为您正在做的事情在C ++ 11中可能还可以……