из статьи доктора Доббса о слабых указателях, я думаю, этот пример легче понять (источник: 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;
}
Этот код имеет ту же проблему, что и предыдущий пример, хотя и в более тонкой форме. Когда он создан, объект shared_pt
r sp1
владеет вновь выделенным ресурсом. Код внутри функции-члена S::dangerous
не знает об этом shared_ptr
объекте, поэтому возвращаемый им объект shared_ptr
отличается от sp1
. Копирование нового объекта shared_ptr
в sp2
не помогает; когда sp2
выходит из области действия, он освобождает ресурс, а когда sp1
выходит из области действия, он снова освобождает ресурс.
Чтобы избежать этой проблемы, используйте шаблон класса enable_shared_from_this
. Шаблон принимает один аргумент типа шаблона, который является именем класса, который определяет управляемый ресурс. Этот класс, в свою очередь, должен быть открыт из шаблона; как это:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
Когда вы делаете это, имейте в виду, что объект, для которого вы вызываете shared_from_this
, должен принадлежать объекту shared_ptr
. Это не сработает:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}