C++03 12.4/12对通过指针显式调用基类析构函数有何说明



根据C++03 12.4/12,当显式调用析构函数时

如果对象不是析构函数的类类型,也不是从析构函数类类型派生的类,则程序具有未定义的行为

所以我有这个代码:

class Base {};
class Derived : public Base {};
char memory[100];
new(memory) Derived();
Base* ptr = (Base*)memory;
ptr->~Base();

这里的对象类型是Derived,"析构函数的类类型"是Base,因此根据标准措辞,看起来没有UB的依据。

那么,上面的代码是否根据标准生成UB?

正确,没有未定义的行为。

相比之下,根据涉及的类型,在这种情况下有潜在的UB:

Base *ptr = new Derived();
delete ptr;

原因是对于某些类型,实现可能已经应用了从Derived*Base*的调整。因此,如果没有指向完整对象的指针,就无法正确释放内存分配。虚拟析构函数确保Base子对象为实现提供足够的信息来恢复(虚拟调用机制必须能够恢复Derived*指针,才能将其作为this传递)。

但在你的例子中,内存并没有被释放,所以没有动机让它成为UB。当然,这仍然是一个坏主意,因为从概念上讲,Derived对象处于损坏状态。您甚至没有合法的方式来调用~Derived。在您的示例中,尽管这两种类型都是可破坏的,所以不需要来调用其中任何一种的析构函数。

它不是UB,因为这两个类都有平凡的析构函数,因此调用析构函数的效果与not调用析构因子的效果相同(no当然不是UB)。

如果我错了,请纠正我,我认为没有未定义的行为,但从人性(或可维护性)的角度来看,仍然应该避免。但是,考虑一下Derived正在创建某种类型的成员,例如共享指针(即使在例外情况下,这也不是不典型的:)。我在我的机器上和代码板上都试过这个代码:

class Base {
public:
  boost::shared_ptr<int> x;
};
class Derived : public Base {
public:
  boost::shared_ptr<int> y;
};

int main(int argc, char *argv[]) {
  boost::shared_ptr<int> xx(new int(0xff));
  boost::shared_ptr<int> yy(new int(0xaa));
  int memory[100];
  for(int i=0; i<100; i++)
    memory[i] = 0;
  Derived* foo = new(memory) Derived();
  foo->x = xx;
  foo->y = yy;
  (*foo->y)--;
  Base* ptr = (Base*)foo;
  ptr->~Base();
  Derived* bar = new(memory) Derived();
  bar->x = xx;
  bar->y = yy;
  foo->~Derived();
  return 0;
}

这里是shared_ptryy没有发布,没有人可以保证永远不会忘记Derived不应该提供任何类型的东西。

最新更新