Какова полезность `включить общий доступ из этого"?
я наткнулся enable_shared_from_this
во время чтения наддува.Примеры Asio и после прочтения документации я все еще теряюсь в том, как это должно правильно использоваться. Может кто-нибудь, пожалуйста, дайте мне пример и/или и объяснение, когда использование этого класса имеет смысл.
6 ответов:
это позволяет вам получить действительный
shared_ptr
экземплярthis
, когда у вас естьthis
. Без него у вас не было бы возможности получитьshared_ptr
доthis
, Если вы уже участник. Этот пример из boost документация для enable_shared_from_this:class Y: public enable_shared_from_this<Y> { public: shared_ptr<Y> f() { return shared_from_this(); } } int main() { shared_ptr<Y> p(new Y); shared_ptr<Y> q = p->f(); assert(p == q); assert(!(p < q || q < p)); // p and q must share ownership }
метод f () возвращает допустимое
shared_ptr
, хотя у него не было экземпляра члена. Обратите внимание, что вы не можете просто сделать это:class Y: public enable_shared_from_this<Y> { public: shared_ptr<Y> f() { return shared_ptr<Y>(this); } }
общий указатель, который этот возвращенный будет иметь другой счетчик ссылок от "правильного", и один из них в конечном итоге потеряет и удержит висячую ссылку при удалении объекта.
enable_shared_from_this
стал частью стандарта C++ 11. Вы также можете получить его оттуда, а также от повышения.
из статьи доктора Доббса о слабых указателях, я думаю, что этот пример легче понять (источник:http://drdobbs.com/cpp/184402026):
...такой код не будет работать правильно:
int *ip = new int; shared_ptr<int> sp1(ip); shared_ptr<int> sp2(ip);
ни один из двух
shared_ptr
объекты знают о другом, поэтому оба будут пытаться освободить ресурс, когда они будут уничтожены. Это обычно приводит к проблемам.аналогично, если функция-член нужен
shared_ptr
"объект", которому принадлежит объект, на который он вызывается, он не может просто создать объект на лету:struct S { shared_ptr<S> dangerous() { return shared_ptr<S>(this); // don't do this! } }; int main() { shared_ptr<S> sp1(new S); shared_ptr<S> sp2 = sp1->dangerous(); return 0; }
этот код имеет ту же проблему, что и в предыдущем примере, хотя и в более тонкой форме. Когда он построен, то г
sp1
владеет вновь выделенным ресурсом. Код внутри функции-членаS::dangerous
не знает об этом
вот мое объяснение, с точки зрения гаек и болтов (верхний ответ не "щелкнул" со мной). * Обратите внимание, что это результат исследования источника для shared_ptr и enable_shared_from_this, который поставляется с Visual Studio 2012. Возможно, другие компиляторы реализуют enable_shared_from_this по-разному...*
enable_shared_from_this<T>
добавляет частнаяweak_ptr<T>
экземплярT
, которая держит 'один истинный счетчик ссылок ' для примераT
.Итак, когда вы впервые создаете
shared_ptr<T>
на новый T*, что T * ' S внутренний weak_ptr инициализируется с refcount 1. Новыйshared_ptr
в основном спиной к этомуweak_ptr
.
T
может тогда, в своих методах, вызватьshared_from_this
чтобы получить экземплярshared_ptr<T>
это спиной к тому же внутренне сохраненному отсчету ссылок. Таким образом, у вас всегда есть одно место, гдеT*
' s ref-count хранится вместо того, чтобы иметь несколькоshared_ptr
экземпляры, которые не знают друг о друге, и каждый думает, что ониshared_ptr
это отвечает за ref-подсчетT
и удаление его, когда их ref-count достигает нуля.
обратите внимание, что использование boost::intrusive_ptr не страдает от этой проблемы. Это часто более удобный способ обойти эту проблему.
это точно то же самое в c++11 и более поздних версиях: это включить возможность возврата
this
как общий указатель сthis
дает вам исходный указатель.другими словами, это позволяет превратить код, как это
class Node { public: Node* getParent const() { if (m_parent) { return m_parent; } else { return this; } } private: Node * m_parent = nullptr; };
в:
class Node : std::enable_shared_from_this<Node> { public: std::shared_ptr<Node> getParent const() { std::shared_ptr<Node> parent = m_parent.lock(); if (parent) { return parent; } else { return shared_from_this(); } } private: std::weak_ptr<Node> m_parent; };
другой способ-добавить
weak_ptr<Y> m_stub
членаclass Y
. Тогда напишите:shared_ptr<Y> Y::f() { return m_stub.lock(); }
полезно, когда вы не можете изменить класс, из которого вы производите (например, расширение библиотеки других людей). Не забудьте инициализировать элемент, например, с помощью
m_stub = shared_ptr<Y>(this)
, он действителен даже во время конструктора.это нормально, если есть больше заглушек, как этот в иерархии наследования, это не предотвратит уничтожение объекта.
Edit: как правильно указано пользователем nobar, код уничтожит объект Y, когда назначение будет завершено, и временные переменные будут уничтожены. Поэтому мой ответ неверен.