общие ptr и слабые различия ptr



Я читаю книгу Скотта Мейерса " эффективный C++". Было упомянуто, что есть tr1::shared_ptr и tr1::weak_ptr действуют как встроенные указатели, но они отслеживают сколько tr1::shared_ptrs указывает на объект.



это называется подсчетом ссылок. Это хорошо работает в предотвращении утечек ресурсов в ациклических структурах данных, но если два или более объектов содержат tr1::shared_ptrs Так что цикл формируется, цикл может держать отсчет ссылок друг друга выше нуля, даже если все внешние указатели чтобы цикл был уничтожен.



вот тут tr1::weak_ptrs войти.



мой вопрос заключается в том, как циклические структуры данных делают отсчет ссылок выше нуля. Я прошу пример программы на C++. Как проблема решается с помощью weak_ptrs? (опять же, с примером пожалуйста).

714   5  

5 ответов:

A shared_ptr обертывает механизм подсчета ссылок вокруг необработанного указателя. Так что для каждого экземпляра shared_ptr счетчик ссылок увеличивается на единицу. Если два share_ptr объекты ссылаются на друг друга, они никогда не будут удалены, потому что они никогда не будут в конечном итоге с нулевым количеством ссылок.

weak_ptr точки shared_ptr но не увеличивает его счетчик ссылок.Это означает, что объект underying все еще может быть удален, даже если есть weak_ptr ссылка на оно.

способ, которым это работает, состоит в том, что weak_ptr можно использовать для создания shared_ptr для тех, кто хочет использовать базовый объект. Если, однако, объект уже был удален, то пустой экземпляр a shared_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_ptr is что за weak_ptr позволяет сохранить объект счетчика ссылок после освобождения фактического объекта. В результате, если вы держите много shared_ptr на std::set фактические объекты будут занимать много памяти, если они достаточно велики. Эта проблема может быть решена с помощью . В этом случае, вы должны обеспечить weak_ptr срок хранения в контейнере не истек до его использования.

Comments

    Ничего не найдено.