C ++: константные ссылки и порядок инициализации - PullRequest
3 голосов
/ 13 октября 2011

Мне интересно, пользуюсь ли я следующим подходом:

  • Я хочу создать родительский класс (класс A), этот класс должен владеть экземпляром данного класса "Foo"
  • Я хочу, чтобы родительский класс владел дочерним членом класса (класс B), и этот член должен иметь ссылку на член foo родительского класса.

Кажется, что приведенный ниже код работает, но мне интересно, повезло ли мне, что компилятор был достаточно сочувствующим.

Для ясности я добавил комментарий и свой вопрос в комментарии ниже.

Спасибо!

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 ]

6 голосов
/ 13 октября 2011

Нет, это сломано.Ваш mB будет содержать ссылку на то, что вы передали конструктору объекта A, а не на mFoo.Вместо этого вы должны сказать:

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

Обратите внимание, что mB является копией аргумента конструктора, а не ссылкой, поэтому ваша функция MyTest в порядке.

3 голосов
/ 13 октября 2011

Поскольку вы хотите, чтобы ваш B объект содержал ссылку на член родителя, вы должны инициализировать mB с mFoo, а не foo.

Вы правы в том, что порядок переменных-членов важен, поскольку он определяет порядок инициализации. Может показаться удивительным, что порядок инициализаторов в конструкторе не определяет порядок их вызова! См. Порядок оценки списка инициализации конструктора .

...