Как инициализировать shared_ptr, который является членом класса? - PullRequest
35 голосов
/ 23 августа 2010

Я не уверен в хорошем способе инициализации shared_ptr, который является членом класса. Можете ли вы сказать мне, подходит ли способ, который я выбираю в C::foo(), или есть лучшее решение?

class A
{
  public:
    A();
};

class B
{
  public:
    B(A* pa);
};

class C
{
    boost::shared_ptr<A> mA;
    boost::shared_ptr<B> mB;
    void foo();
};

void C::foo() 
{
    A* pa = new A;
    mA = boost::shared_ptr<A>(pa);
    B* pB = new B(pa);
    mB = boost::shared_ptr<B>(pb);
}

1 Ответ

30 голосов
/ 23 августа 2010

Ваш код достаточно корректен (он работает), но вы можете использовать список инициализации, например, так:

C::C() :
  mA(new A),
  mB(new B(mA.get())
{
}

Что еще более правильно и безопасно.

Если,по любой причине, new A или new B throws, у вас не будет утечки.

Если new A throws, то память не выделяется, и исключение также прерывает ваш конструктор.Ничего не было построено.

Если new B сгенерирует, и исключение все равно прервет ваш конструктор: mA будет уничтожен должным образом.

Конечно, поскольку экземпляр B требуетуказатель на экземпляр A, порядок объявления членов имеет значение .

Порядок объявления членов является правильным в вашем примере, но если он был обратным, то ваш компилятор будетвозможно, вы будете жаловаться на то, что mB инициализируется до mA, а создание экземпляра mB, скорее всего, завершится неудачей (поскольку mA еще не было бы сконструировано, поэтому вызов mA.get() вызывает неопределенное поведение).1030 * Я бы также предложил, чтобы вы использовали shared_ptr<A> вместо A* в качестве параметра для вашего B конструктора (, если имеет смысл и если вы можете принять небольшие накладные расходы).Возможно, это было бы безопаснее.

Возможно, гарантировано, что экземпляр B не может жить без экземпляра A, и тогда мой совет неприменим, но у нас здесь недостаточно контекста длядать четкий совет по этому поводу.

...