tags:

views:

155

answers:

3
+2  Q: 

Destructor order

I have a C++ class hierarchy that looks something like this:

class A;

class B
{
public:
    B( A& a ) : a_( a )
    {
    };

private:
    A& a_;
};

class MyObject
{
public:
    MyObject() : b_( a_ )
    {
    };

private:
    A a_;
    B b_;
};

Occasionally, it will happen that in B's destructor I will get invalid access exceptions relating to its reference of A. It appears that A is destroyed before B.

Is there something inherently wrong with using class members to initialize other members? Is there no guarantee of the order of destruction?

Thanks, PaulH

+6  A: 

EDIT: I missed the MyObject part of your question so my original answer will probably not be of much help. I guess your problem lies in the code you did not post, the stripped-down example should work fine.


Class B does not “own” the object passed by reference, therefore the objects a and b have different life cycles. If the object refered to by B::a_ is destroyed, B's destructor will access an invalid reference.

Some code to explain what I mean:

class A;

class B {
public:
    B(A a) : a_(a) {}  // a is copied to a_
    ~B() { /* Access a_ */ }
private:
    A a_;
};

class C {
public:
    C(A& a) : a_(a) {}  // a_ is a reference (implicit pointer)
                        // of an external object.
    ~C() { /* Access a_ */ }
private:
    A& a_;
};


int main(int argc, char** argv) {
    A* a = new A();

    B b(*a);
    C c(*a);

    delete a;
    // Now b has a valid copy of a, c has an invalid reference.
}
Ferdinand Beyer
Hum, did you mean to have a destructor in B that was doing something to A?
ruibm
Construction order follows declaration order, and destruction order is reversed. In the MyObject example, this means that a_ should be constructed before b_, and a_ should be destroyed after b_. IOWs, you're right that B, as defined, does not own a_ *but*, MyObject, as defined, should guarantee proper construction and destruction order.
Éric Malenfant
@Eric: You are right, I missed the `MyObject` detail.
Ferdinand Beyer
Yup, I agree with Eric, I don't see a problem a with the code in the Question - Members in MyObject are declared in the correct order so that it never crashes.
ruibm
The problem must be elsewhere. Thanks for confirming.
PaulH
+5  A: 

a_ should be constructed before b_, and b_ should be destructed before a_, based on the order you have defined them in MyObject.

chrisbtoo
+6  A: 

In the code above the destruction order is well defined.
The destruction order is the reverse of the creation order.
The creation order is the order the members were declared within the class.
So in this case:

Default Construction:
  a_:  constructed first using default constructor.
  b_:  constructed using a valid a_ passed to the constructor.

Destruction:
  b_:   destroyed first. The destructor can use the reference to a 
        As long as the object has not been copied (see below)
  a_:   destroyed second.

But you have a potential problem if you make a copy of the object using the copy constructor.

The following copy constructor is defined by the compiler:

MyObject::MyObject(MyObject const& copy)
    :a_(copy.a_)
    ,b_(copy.b_)
{}

So you may have a potential problem here. As the copy will contain an object 'b_' that contains a reference that was copied from another object. If the other object is destroyed then this 'b_' will have an invalid reference.

Martin York