问题
Question
What does the C++ standard guarantee about the state of an object in the time after a derived class's destructor executes, but before the base class's destructor executes ? (This is the time when the derived class's subobjects' destructors are being called.)
Example
#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;
}
In this example, a Member
object has a pointer to a Derived
object that owns it, and it attempts to access that Derived
object as it is destructed...even though the destructor for Derived
has already finished.
Which version of *bd
's virtual functions would be called if some subobject called a virtual function after ~Derived()
executes, but before ~Base()
executes? Is it even legal to access *bd
when it's in that state?
回答1:
from n3290 [class.cdtor]
12.7 Construction and destruction 1 For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
回答2:
For me, from [12.4] it clearly stands, that it is not legal:
Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8). [Example: ...]
Despite the lack of definition for no longer exists, I think, I can say that referencing an object which no longer exists results in undefined behaviour.
回答3:
At the moment in time that you're calling b_->f()
, Derived
is in the process of being destructed, but Base
hasn't been destructed yet. You're still in limbo though, because it's Derived::f()
that you're going to be calling.
Edit:
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived from the constructor or destructor’s class, or overriding it in one of the other base classes of the most derived object (1.8). If the virtual function call uses an explicit class member access (5.2.5) and the object-expression refers to the object under construction or destruction but its type is neither the constructor or destructor’s own class or one of its bases, the result of the call is undefined.
C++0x working draft Sec 12.7 par 4
来源:https://stackoverflow.com/questions/11235357/the-state-of-an-object-between-a-call-to-derived-and-base