调用~Derived()和~Base()之间的对象状态

Nat*_*ohl 6 c++ destructor object-lifetime

题

在派生类的析构函数执行之后但在基类的析构函数执行之前,C++标准对于对象状态的保证是什么?(这是派生类的子对象的析构函数被调用的时间.)

例

#include <string>
struct Base;

struct Member {
  Member(Base *b);
  ~Member();
  Base *b_;
};

struct Base {
  virtual void f() {}
  virtual ~Base() {}
};

struct Derived : Base {
  Derived() : m(this) {}
  virtual ~Derived() {}  
  virtual void f() {}
  std::string s; 
  Member m;
};

Member::Member(Base *b) : b_(b) {}
Member::~Member() {
  // At this point, ~Derived has finished -- can we use b_ as a 
  // Derived* object (i.e. call Derived::f or access Derived::s)?
  b_->f();
}

int main() {
  Base *bd = new Derived;
  delete bd;
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,一个Member对象有一个指向Derived拥有它的对象的指针,它试图在Derived它被破坏时访问该对象......即使析构函数Derived已经完成.

*bd如果某个子对象在~Derived()执行后调用虚函数,但在~Base()执行之前,将调用哪个版本的虚函数?*bd当它处于该状态时访问是否合法?

Raf*_*cki 5

对我来说,从[12.4]可以清楚地看出,它不合法:

一旦为对象调用析构函数,该对象就不再存在; 如果为生命周期结束的对象调用析构函数,则行为未定义(3.8).[例子:...]

尽管缺乏定义不再存在,但我认为,我可以说引用不再存在的对象会导致未定义的行为.


Fer*_*oni 1

来自 n3290 [class.cdtor]

12.7 构造和销毁 1 对于具有非平凡构造函数的对象,在构造函数开始执行之前引用该对象的任何非静态成员或基类会导致未定义的行为。对于具有非平凡析构函数的对象,在析构函数完成执行后引用该对象的任何非静态成员或基类会导致未定义的行为。