Какова польза от "enable shared from this"?
я наткнулся enable_shared_from_this
во время чтения Boost.Примеры ASIO и после прочтения документации я еще не потерян для того, как это должно правильно применяться. Может кто-нибудь, пожалуйста, дайте мне пример и/или и объяснение, когда использование этого класса имеет смысл.
6 ответов
это позволяет получить действительный shared_ptr
экземпляр this
, когда у вас есть this
. Без него, вы бы не shared_ptr
to this
, Если вы уже участник. Этот пример из увеличить документацию для 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*, что внутренний weak_ptr T*инициализируется с пересчетом 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: As правильно указано пользователем nobar, код уничтожит объект Y, когда назначение будет завершено и временные переменные будут уничтожены. Поэтому мой ответ неверен.