общие ptr и слабые различия ptr
Я читаю книгу Скотта Мейерса " эффективный C++". Было упомянуто, что есть tr1::shared_ptr и tr1::weak_ptr действуют как встроенные указатели, но они отслеживают сколько tr1::shared_ptrs указывает на объект.
это называется подсчетом ссылок. Это хорошо работает в предотвращении утечек ресурсов в ациклических структурах данных, но если два или более объектов содержат tr1::shared_ptrs Так что цикл формируется, цикл может держать отсчет ссылок друг друга выше нуля, даже если все внешние указатели чтобы цикл был уничтожен.
вот тут tr1::weak_ptrs войти.
мой вопрос заключается в том, как циклические структуры данных делают отсчет ссылок выше нуля. Я прошу пример программы на C++. Как проблема решается с помощью weak_ptrs? (опять же, с примером пожалуйста).
5 ответов:
A
shared_ptrобертывает механизм подсчета ссылок вокруг необработанного указателя. Так что для каждого экземпляраshared_ptrсчетчик ссылок увеличивается на единицу. Если дваshare_ptrобъекты ссылаются на друг друга, они никогда не будут удалены, потому что они никогда не будут в конечном итоге с нулевым количеством ссылок.
weak_ptrточкиshared_ptrно не увеличивает его счетчик ссылок.Это означает, что объект underying все еще может быть удален, даже если естьweak_ptrссылка на оно.способ, которым это работает, состоит в том, что
weak_ptrможно использовать для созданияshared_ptrдля тех, кто хочет использовать базовый объект. Если, однако, объект уже был удален, то пустой экземпляр ashared_ptrвозвращается. Поскольку счетчик ссылок на объект не увеличивается сweak_ptrссылка, циклическая ссылка не приведет к тому, что базовый объект не будет удален.
позвольте мне повторить ваш вопрос: "мой вопрос, как циклические структуры данных делают отсчет ссылок выше нуля, пожалуйста, попросите показать пример в программе C++. Как проблема решается с помощью
weak_ptrsопять с примером, пожалуйста."проблема возникает с кодом C++ следующим образом (концептуально):
class A { shared_ptr<B> b; ... }; class B { shared_ptr<A> a; ... }; shared_ptr<A> x(new A); // +1 x->b = new B; // +1 x->b->a = x; // +1 // Ref count of 'x' is 2. // Ref count of 'x->b' is 1. // When 'x' leaves the scope, there will be a memory leak: // 2 is decremented to 1, and so both ref counts will be 1. // (Memory is deallocated only when ref count drops to 0)чтобы ответить на вторую часть вашего вопроса: математически невозможно для подсчета ссылок иметь дело с циклами. Таким образом,
weak_ptr(что в принципе просто урезанная версияshared_ptr)не может используйте для того чтобы разрешить проблему цикла - программист разрешает проблему цикла.чтобы решить ее, программист должен быть в курсе собственности отношения между объектами, или необходимо изобрести отношения собственности, если такое право собственности не существует естественным образом.
приведенный выше код C++ может быть изменен так, что A владеет B:
class A { shared_ptr<B> b; ... }; class B { weak_ptr<A> a; ... }; shared_ptr<A> x(new A); // +1 x->b = new B; // +1 x->b->a = x; // No +1 here // Ref count of 'x' is 1. // Ref count of 'x->b' is 1. // When 'x' leaves the scope, its ref count will drop to 0. // While destroying it, ref count of 'x->b' will drop to 0. // So both A and B will be deallocated.решающий вопрос: может
weak_ptrбудет используется в случае, если программист не может определить отношения собственности и не может установить какое-либо статическое владение из-за отсутствия привилегий или отсутствия информации?ответ: если владение среди объектов неясно,
weak_ptrне может помочь. Если есть цикл, то программист должен найти его и разорвать. Альтернативным решением является использование языка программирования с полной сборкой мусора (например: Java, C#, Go, Haskell) или использование консервативного (=несовершенного) сборщик мусора, который работает с C / C++ (например: Boehm GC).
для будущих читателей.
Просто хочу отметить, что объяснение, данное атомом, отлично, вот рабочий код#include <memory> // and others using namespace std; class B; // forward declaration // for clarity, add explicit destructor to see that they are not called class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } }; class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } }; shared_ptr<A> x(new A); //x->b share_ptr is default initialized x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr x->b->a = x; cout << x.use_count() << endl;
слабые указатели просто " наблюдают "за управляемым объектом; они не" поддерживают его жизнь " или не влияют на его время жизни. В отличие от
shared_ptr, когда последнийweak_ptrвыходит из области видимости или исчезает, указанный объект все еще может существовать, потому чтоweak_ptrне влияет на время жизни объекта - он не имеет права собственности. Элементweak_ptrможет использоваться для определения того, существует ли объект, и для предоставленияshared_ptrЭто может быть использовано для ссылки на него.определение
weak_ptrпредназначен чтобы сделать его относительно надежным, так что в результате есть очень мало вы можете сделать непосредственно сweak_ptr. Например, вы не можете разыменовать его; ниoperator*, ниoperator->определяется дляweak_ptr. Вы не можете получить доступ к указателю на объект с ним - нет
все вышеприведенные ответы неверны.
weak_ptrне используется для разрыва циклических ссылок, они имеют другое назначение.в принципе, если все
shared_ptr(s)было созданоmake_shared()илиallocate_shared()звонки, вы никогда не будете нуждатьсяweak_ptrЕсли у вас нет других ресурсов, кроме памяти для управления. Эти функции создаютshared_ptrсчетчик ссылок объекта с самим объектом, и память будет освобождена в то же время.единственная разница между
weak_ptrиshared_ptris что заweak_ptrпозволяет сохранить объект счетчика ссылок после освобождения фактического объекта. В результате, если вы держите многоshared_ptrнаstd::setфактические объекты будут занимать много памяти, если они достаточно велики. Эта проблема может быть решена с помощью . В этом случае, вы должны обеспечитьweak_ptrсрок хранения в контейнере не истек до его использования.
Comments