Создать boost :: shared_ptr для существующей переменной - PullRequest
27 голосов
/ 11 декабря 2011

У меня есть существующая переменная, например,

int a = 3;

Как теперь я могу создать boost::shared_ptr до a?Например:

boost::shared_ptr< int > a_ptr = &a; // this doesn't work

Ответы [ 4 ]

43 голосов
/ 11 декабря 2011

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

int *a=new int;
boost::shared_ptr<int> a_ptr(a);

Это говорит о том, что вы совершенно определенно не хотите помещать переменные стека в shared_ptr BAD THINGSБУДЕТ ПРОИЗОШЛО

Если по какой-то причине функция принимает shared_ptr, и у вас есть только стек, вы можете сделать это:

int a=9;
boost::shared_ptr<int> a_ptr=boost::make_shared(a);

См. Здесь:

http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/make_shared.html

также стоит отметить, что shared_ptr соответствует стандарту c ++ 11, если вы можете его использовать.Вы можете использовать auto в сочетании с make_shared, как отмечает Херб Саттер в разговоре о сборке.

#include <memory>

int a=9;
auto a_ptr=std::make_shared(9);
32 голосов
/ 12 декабря 2011

Во-первых, у вас есть ошибка, потому что shared_ptr не будет автоматически преобразовываться из указателя соответствующего типа.Вы должны четко указать, что вы хотите сделать:

int a = 3;
::boost::shared_ptr< int > a_ptr(&a); // DO NOT DO THIS!

У вас есть другая проблема.Представьте себе эффект этого кода:

int a = 3;
delete &a;

В первом примере, который я привел, это неизбежно произойдет, даже если это не совсем так прямо.shared_ptr вся причина существования заключается в удалении вещей, когда все указатели на него исчезают.Это, конечно, вызовет все виды странного поведения.

У вас есть два способа решения этой проблемы.Одним из них является создание чего-то, что можно удалить.Другой - убедиться, что shared_ptr на самом деле не удаляет то, на что он указывает.У каждого есть свои плюсы и минусы.

Создание чего-то, что можно удалить:

Плюсы:

  • Просто и легко.
  • Вы надеваетеНе нужно беспокоиться о времени жизни объекта.

Минусы:

  • Немного на медленной стороне, поскольку это потребует выделения кучи или двух.
  • Полученный shared_ptr будет ссылаться на копию, поэтому изменения в a не будут отражены в значении того, на что он указывает.

Как это сделать:

::boost::shared_ptr<int> a_ptr(::boost::make_shared(a));

Это довольно похоже на (и это также будет работать):

::boost::shared_ptr<int> a_ptr(new int(a));

Но это немного более эффективно.::boost::make_shared делает некоторую магию, чтобы распределить счетчик ссылок и объект в непрерывной памяти, что экономит на вызовах распределителю и улучшает локальность ссылок.

Делая так, чтобы shared_ptr фактически не удалял то, что онуказывает на:

Плюсы:

  • Быстрее, хотя это все еще включает выделение кучи для счетчика ссылок
  • Непосредственно решает проблему под рукой (вещь, которую вы 'повторное указание не может быть удалено).
  • * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * при его использовалось бы указывать a.*

    Минусы:

    • Требуется знать немного больше о том, как работает shared_ptr, а это значит, что люди, читающие ваш код, тоже должны знать.
    • Если выповторное указание выходит из области видимости раньше, чем все shared_ptr, которые указывают на это, затем эти указатели становятся висящими, и это плохо.
    • Предыдущий пункт делает это очень рискованным решением .Я бы вообще этого избегал.

    Как это сделать:

    Где-то за пределами функции (возможно, в анонимном пространстве имен):

    void do_nothing_deleter(int *)
    {
        return;
    }
    

    А потом вфункция:

    int a = 3;
    ::boost::shared_ptr a_ptr(&a, do_nothing_deleter);
    
15 голосов
/ 11 декабря 2011

То, что вы написали, не сработает, потому что вы ищете shared_ptr конструктор explicit, поэтому вам нужно написать его так

boost::shared_ptr<int> a_ptr(&a); // Don't do that!

Проблема с в том, что , однако, заключается в том, что delete будет вызываться для сохраненного значения a_ptr. Так как в вашем примере a имеет автоматическую продолжительность хранения, это очень плохо . Поэтому мы также передаем пользовательское средство удаления:

boost::shared_ptr<int> a_ptr(&a, noop_deleter);

Реализация noop_deleter для C ++ 11:

auto noop_deleter = [](int*) {};

C ++ 03 версия:

// Can't be put in local scope
struct {
    void
    operator()(int*) const
    {}
} noop_deleter;
8 голосов
/ 11 декабря 2011

Вы не можете создать boost :: shared_ptr для существующей переменной. Элементы, сохраненные в boost :: shared_ptr, сохраняются при создании.

Однако вы можете сделать boost :: shared_ptr, который является копией существующей переменной.

Например

int a = 3; // Existing variable
boost::shared_ptr<int> aCopy = boost::make_shared<int>(a); //Create copy with value of a

Обратите внимание, что вам нужно включить <boost/make_shared.hpp> для make_shared.

...