ссылка на велотренажер boost shared_ptr?

Из документации по boost по boost :: shared_ptr:

Поскольку реализация использует подсчет ссылок, циклы экземпляров shared_ptr не будут возвращены. Например, если main () содержит shared_ptr для A, который прямо или косвенно удерживает shared_ptr обратно в A, счетчик использования A будет равен 2. Уничтожение исходного shared_ptr оставит A висящим со счетчиком использования 1. Используйте weak_ptr для «разорвать циклы».

Я не мог понять этот абзац, не могли бы вы привести минимальный пример этой ситуации и объяснить последствия.


person Jichao    schedule 24.04.2013    source источник


Ответы (4)


Как работает умный указатель? Они запоминают count интеллектуальных указателей, которые указывают на объект, и увеличивают это count, когда новый общий указатель берет на себя управление объектом, и уменьшают count, если общий указатель теряет контроль над объектом.

Предположим, у вас есть класс:

class A{
public:
    A(){std::cout << "Object created" << std::endl;}
    ~A(){std::cout << "Object destroyed" << std::endl;}
    void setSibling(boost::shared_ptr<A> &sibling){
        m_sibling = sibling;
    }
private:
    boots::shared_ptr<A> m_sibling;    
};

и foo ():

void foo(){
    //count increases from 0 to 1 (ptr take control on instance of A)
    boost::shared_ptr<A> ptr(new A); 

    //count increases from 1 to 2 (m_sibling take control on instanse of A)
    ptr->setSibling(ptr); 

    //count decreases from 2 to 1 
    //(ptr is destroyed and lose control on instance of A)
    return; 
}

M_sibling потеряет контроль при вызове ~ A (), но ~ A () будет вызываться только тогда, когда все общие указатели потеряют контроль. Итак, после вызова foo вы не можете получить доступ к этому экземпляру A. Но счетчик равен 1, и общий указатель НЕ удалит этот объект, поэтому у вас есть утечка памяти и ресурсов.

См. Документацию для weak_ptr в усилении, чтобы узнать, как их использовать с shared_ptr.

Вкратце: слабый указатель похож на общий указатель, но не увеличивает count. Если у вас есть экземпляр weak_ptr, созданный из shared_ptr для объекта, который был уничтожен, экземпляр weak_prt выдаст исключение (segfault не произойдет), если вы попытаетесь получить доступ к необработанному указателю. В документации boost есть пример того, как правильно использовать weak_prt, используя метод weak_ptr::lock().

person JustAnotherCurious    schedule 24.04.2013
comment
не забывайте enable_shared_from_this !! - person trompa; 24.04.2013
comment
Как работает умный указатель? Как они делают, что делают, не проблема. - person curiousguy; 18.06.2018

Представьте себе сокровище.
Ваш друг берет сундук и кладет в него немного золота. И еще он делает карту.
И это волшебная карта с одним пунктом: если вы сожжете последнюю копию карты, сокровище и золото исчезнут.
Ваш друг кладет карту в сундук вправо над золотом, делает для вас вторую карту и закрывает сундук с первой картой внутри.
Он дает вам вторую копию карты и исчезает вместе с сокровищами.
Вопрос в том, что произойдет, если вы сожжете свою карту ?
Ответ: Ничего, сокровище еще где-то.

Почему? Потому что последняя копия карты все еще в сундуке!

person Andrey Volk    schedule 24.04.2013

Вот пример (обратите внимание, что ~A здесь никогда не вызывается):

#include <boost/shared_ptr.hpp>
#include <iostream>

using boost::shared_ptr;
struct A
{
    ~A()
    {
        std::cout << "~A()" << std::endl;
    }
    void set_shared_ptr(const shared_ptr<A> &p)
    {
        p_ = p;
    }
    shared_ptr<A> p_;
};

int main()
{
  shared_ptr<A> q(new A);
  q->set_shared_ptr(q);
  q.reset();
}
person Igor R.    schedule 24.04.2013

Из документации Boost

Поскольку реализация использует подсчет ссылок, циклы экземпляров shared_ptr не будут возвращены.

Ты пишешь:

Я не мог понять этот абзац

Это хорошо; это потому что ты умный. Абзац вообще не имеет смысла. Если вы думаете, что понимаете, значит, нет.

Циклы не могут быть восстановлены, ну, потому что существует циклическая зависимость! Никакая часть цикла не может быть восстановлена ​​до восстановления остальной части цикла, поэтому вам придется уничтожить каждый объект до его уничтожения начинается. Если у вас есть циклические зависимости, это часть сломанного дизайна вашей программы. Не пытайтесь обвинять умные указатели (или подсчет ссылок).

Никакая часть фундаментальной проблемы зависимости никоим образом не связана с деталями реализации интеллектуальных указателей; это вызвано самим определением владеющего интеллектуального указателя: принадлежащий объект не будет уничтожен до того, как запустится деструктор (последнего) владеющего указателем.

И, конечно же, это справедливо и для интеллектуальных указателей исключительного владения, таких как std::unique_ptr, которые даже не имеют счетчика ссылок!

Используйте weak_ptr, чтобы «разорвать циклы».

Не надо. Избегайте циклов. Вы не можете «разорвать» цикл. Не существует такой вещи, как «разрыв» цикла.

Документация по Boost здесь хуже, чем бесполезна. Это опасно. Он смешивает инвариант и реализацию на таком уровне, что демонстрирует очень плохое понимание семантики интеллектуальных указателей.

И это многое говорит о способности фальшивой информации и антипаттернов самовоспроизводиться!

person curiousguy    schedule 27.12.2016