Подтвердить что ты не робот

Можно ли использовать указатель "this" в списке инициализации?

У меня есть два класса с отношения родитель-ребенок (The Parent класс "имеет-а" Child класс), и Child класс имеет указатель обратно к Parent. Было бы неплохо инициализировать указатель родителя при построении потомка следующим образом:

class Child;
class Parent;

class Child
{
public:
 Child (Parent* parent_ptr_) : parent_ptr(parent_ptr_) {};

private:
 Parent* parent_ptr;
};

class Parent
{
public:
    Parent() : child(this) {};

private:
    Child child;
}

Теперь я знаю, что люди рекомендуют не использовать this в списке инициализации, и в C++ FAQ говорится, что я получу предупреждение компилятора (кстати, на VS2010, я не получаю предупреждение), но мне действительно нравится это лучше, чем вызов некоторая функция множества в конструкторе Parent. Мои вопросы:

  • Является ли родительский this указатель четко определенным при создании Child объекта?
  • Если так, почему считается плохой практикой использовать его, как указано выше?

Спасибо,

Боаз

РЕДАКТИРОВАТЬ: Спасибо Тимбо, это действительно дубликат (да, я даже выбрал те же имена классов). Итак, давайте добавим некоторую ценность: как насчет ссылок? Возможно ли/безопасно ли сделать следующее? :

class Child
{
public:
 Child (Parent& parnet_ptr_) : parent_ptr(parent_ptr_) {};

private:
 Parent* parent_ptr;
};

class Parent
{
public:
    Parent() : child(*this) {};

private:
    Child child;
}
4b9b3361

Ответ 1

Да. Безопасно использовать указатель this в списке инициализации , если он не используется для доступа к неинициализированным членам или виртуальным функциям, прямо или косвенно, поскольку объект еще не полностью сконструирован. Объект child может хранить указатель this Parent для дальнейшего использования!

Ответ 2

Родительский указатель this в терминах "указатель" четко определен (иначе как родительский конструктор знает, на каком экземпляре он работает?), но:

  • поля, объявленные после объекта Child, еще не инициализированы;
  • код в конструкторе еще не запущен;
  • обычные предупреждения об использовании виртуальных элементов из конструктора применяются 1.

Итак, родительский объект вообще находится в противоречивом состоянии; все, что дочерний объект будет делать при построении на родительском объекте, будет выполняться на полуконструированном объекте, и это вообще не очень хорошо (например, если он называет "нормальные" методы, которые полагаются на то, что объект полностью построен - вы можете попасть в "невозможные" коды кода).

Тем не менее, если весь дочерний объект с родительским указателем в его конструкторе должен хранить его, чтобы использовать его позже (= > , когда он будет фактически создан), там нет ничего плохого.


  • I.e., виртуальная отправка не работает в конструкторах, так как vtable еще не обновлялся конструктором производного класса. См. здесь.

Ответ 3

Поведение хорошо определено, пока вы не пытаетесь разыменовать указатель до тех пор, пока объект Parent не будет полностью сконструирован (как говорит @Sergey в комментарии ниже, если построенный объект фактически получен от Parent, то все его конструкторы должны быть завершены).