Boost :: shared_ptr создан с использованием этого - PullRequest
3 голосов
/ 22 января 2011

Рассмотрим следующий случай:

typedef boost::shared_ptr<B> BPtr;

class A
{
public:
    A() { b_ptr = BPtr(new B); }
    void a_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class B
{
public:
    B() { b_ptr = BPtr(this); }
    void b_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class C
{
public:
    static void c_func(BPtr b_ptr) { /*...*/ }
}

Можно ли создавать экземпляр shared_ptr с помощью this?
Можно ли иметь два объекта shared_ptr, указывающие на один и тот же объект?(например, A :: b_ptr и B :: b_ptr)
Если один из этих двух выйдет из области видимости - будет ли удален экземпляр B?

Я предполагаю, что делаю что-то в корне неправильное.
Я также думал об использовании внедрения зависимостей b_ptr в конструктор B. Но это тоже кажется очень неправильным.

ОБНОВЛЕНИЕ:
Чтобы уточнить - и A, и B должны использовать C:: c_func.В свою очередь, после некоторой обработки C необходимо вызвать функцию обратного вызова в B, которую я не указал выше.На самом деле интересны два случая:

  1. Если есть требование, чтобы C не сохранял состояние - тогда ему нужно получать BPtr как от A, так и от B, как в коде выше.
  2. Если C является состоянием, и A и B создают отдельные экземпляры C, давая BPtr в ctor.

Ответы [ 2 ]

10 голосов
/ 22 января 2011

Можно ли создать экземпляр shared_ptr с этим?

Нет, по крайней мере по нескольким причинам:

  1. Если вы создаете A или B объект в стеке или статически, вы получите shared_ptr "владение" объектом, созданным в стеке;когда объект уничтожен, будет вызван деструктор shared_ptr, который вызовет delete для объекта, и произойдут только плохие вещи.Кроме того, даже если объект создается динамически, вы не знаете наверняка, что может сделать с ним владелец вашего класса: он может назначить его другому интеллектуальному типу указателя, например auto_ptr, который имеет совершенно другую семантику.

  2. В итоге вы получите круговую ссылку.Например, b_ptr принадлежит объект B, членом которого он является.Вам необходимо .reset() вручную, чтобы уничтожить объект B.

Вы можете получить shared_ptr из this с помощью enable_shared_from_this, ноЕсть много предостережений: а именно, вы не можете вызвать enable_shared_from_this в конструкторе.Тем не менее, вы не хотите хранить shared_ptr для объекта внутри самого объекта;это не имеет никакого смысла.

Я предполагаю, что я делаю что-то в корне неправильно.

Да, но поскольку вы еще не сказали, что именно, вы пытаетесь сделать, трудно сказать, что вы должны делать вместо этого.Вы только сказали нам, как вы пытаетесь это сделать, а не то, что вы пытаетесь сделать в первую очередь.

0 голосов
/ 22 января 2011

Я бы порекомендовал вам перепроектировать для использования std :: enable_shared_from_this, например

class B
{
   B();
public:
   std::shared_ptr<B> create() { return std::make_shared<B>(); } // Make sure B is allocated as shared_ptr inorder to ensure that shared_from_this() works.
};

Однако, если это проблема с API, вы можете сделать следующее (хотя я не рекомендую это).

void b_func() { C::c_func(BPtr(this, [](B*){})); } // Empty deleter. Nothing happens when shared_ptr goes out of scope. Note that c_func cannot take ownership of the pointer.
...