C++ : const references and initialization order

198 views Asked by At

I am wondering if I am using the good approach in the following :

  • I want to construct a parent class (class A), this class should own an instance of a given "Foo" class
  • I want the parent class to own a child class member (class B) and this member should have a reference to the foo member of the parent class.

The code below seems to works, however I am wondering whether I was just "lucky" that the compiler was sympathetic enough.

For clarity, I added comment and my question in the comments below.

Thanks !

struct Foo
{
  std::string mValue;
};

class B
{
public:
  B(const Foo & foo) : mFoo_External(foo) {}
private:
  const Foo & mFoo_External; //this is an external reference to the member 
                             //(coming from A)
};

class A
{
public:
  //Here is the big question 
  //Shall I use : 
  //  A(const Foo & foo) : mFoo(foo), mB(mFoo) {}  
  //  or the declaration below
  A(const Foo & foo) : mFoo(foo), mB(foo) {}
private:
  //According to my understanding, the declaration 
  //order here *will* be important
  //(and I feel this is ugly)
  const Foo  mFoo;
  B mB;
};



void MyTest()
{
  std::auto_ptr<Foo> foo(new Foo());
  foo->mValue = "Hello";
  A a( *foo);
  foo.release();

  //At this point (after foo.release()), "a" is still OK 
  //(i.e A.mB.mFooExternal is not broken, although foo is now invalid)
  //
  //This is under Visual Studio 2005 : 
  //was I lucky ? Or is it correct C++ ?
}
2

There are 2 answers

7
Kerrek SB On BEST ANSWER

No, this is broken. Your mB will hold a reference to whatever you passed to the constructor of the A object, not to mFoo. Instead, you should say:

A(const Foo & foo) : mFoo(foo), mB(mFoo) { }

Note that mB is a copy of the constructor argument, and not a reference, so your MyTest function is fine.

0
Mark Ransom On

Since you want your B object to hold a reference to the parent's member, you must initialize mB with mFoo not foo.

You are correct that the order of the member variables is important, since it determines the order of the initialization. It might come as a surprise that the order of the initializers in the constructor does not determine the order they are called! See Constructor initialization-list evaluation order.