Зачем нужен boost::weak_ptr?
Я относительно недавно работаю с boost и многое еще не понятно. Вопрос по указателям: зачем нужны weak_ptr
, что они дают такое, чего не дают smart_prt
? Почему нельзя использовать только smart_prt
?
Я относительно недавно работаю с boost и многое еще не понятно. Вопрос по указателям: зачем нужны weak_ptr
, что они дают такое, чего не дают smart_prt
? Почему нельзя использовать только smart_prt
?
Попробую объяснить "на пальцах".
Вначале пример:
shared_ptr<A> a1( new A() );
// тут счетчик == 1, мы создали объект
// и у нас один сильный указатель на него
shared_ptr<A> a2 = a1;
// тут счетчик == 2
// мы имеем два сильных указателя на один объект
weak_ptr<A> w = a2;
// тут счетчик снова == 2
// мы имеем два сильных указателя на один объект
// и один слабый
a2.reset();
// тут счетчик == 1, один сильный указатель теперь пустой
// но объект A жив и доступен через сильный указатель a1
// так как на данный момент существует один сильный указатель
// на объект (a1), то мы можем из слабого указателя получить сильный
a2 = w.lock();
// тут счетчик == 2,
// мы получили вполне работоспособный сильный указатель из слабого
a2.reset();
a1.reset();
// тут счетчик == 0, нет ни одного сильного указателя
// Объект автоматически умер при вызове a1.reset()
// и попытка получить сильный указатель из слабого вернет пустой shared_ptr
shared_ptr<A> a0 = w.lock();
// вот это условие будет выполнено
a0.get() == 0
Внутри сильный указатель представляет из себя структуру типа:
struct storage
{
Object* pointer;
long refs;
}
«Слабые» указатели используются, вообще, не только в Бусте. Это очень распространённая концепция.
Ведь smart_ptr и weak_ptr — это попытка реализовать что-то вроде сборки мусора. Объект существует до тех пор, пока на него есть хотя бы один указатель. Правильнее сказать, хотя бы один неслабый указатель.
Самый распространённый и очевидный пример — кэширование. Если у Вас в кэше сохранится сильный указатель, то он не даст объекту удалиться. Обычно, всё-таки, хочется, чтобы в определении времени жизни объекта кэш не участвовал.
Слабые указатели нужны, в том числе, для предотвращения циклических ссылок. Если два объекта ссылаются друг на друга «жестко», очевидно, они не удалятся, если не предпринять дополнительных действий («разорвать» цикл, удалить один из элементов цикла вручную). Обычно смотрят кто кем владеет и если объект A не владеет объектом B, то он хранит мягкий указатель на B.
Для примера: некий список владеет элементами и хранит жесткие указатели на них. Элементы могут хранить мягкий указатель на список, чтобы, например, удалить себя из него. Если бы все указатели были жесткими, пришлось бы совершать дополнительные действия при удалении списка: удалять все его элементы (предположим, что у нас самописный список, а не из STL).