Получаем повышение :: shared_ptr для этого - PullRequest
76 голосов
/ 27 сентября 2008

Я широко использую boost:shared_ptr в своем коде. Фактически, большинство объектов, размещенных в куче, удерживаются shared_ptr. К сожалению, это означает, что я не могу передать this в любую функцию, которая принимает shared_ptr. Рассмотрим этот код:

void bar(boost::shared_ptr<Foo> pFoo)
{
    ...
}

void Foo::someFunction()
{
    bar(this);
}

Здесь есть две проблемы. Во-первых, это не скомпилируется, потому что конструктор T * для shared_ptr является явным. Во-вторых, если я заставлю его строить с bar(boost::shared_ptr<Foo>(this)), я создам второй общий указатель на мой объект, который в конечном итоге приведет к двойному удалению.

Это подводит меня к моему вопросу: существует ли какой-либо стандартный шаблон для получения копии существующего общего указателя, который, как вы знаете, существует из метода одного из этих объектов? Является ли использование навязчивого подсчета ссылок моим единственным вариантом здесь?

Ответы [ 6 ]

102 голосов
/ 27 сентября 2008

Вы можете получить из enable_shared_from_this , а затем вы можете использовать «shared_from_this ()» вместо «this» для создания общего указателя на ваш собственный объект self.

Пример в ссылке:

#include <boost/enable_shared_from_this.hpp>

class Y: public boost::enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(new Y);
    shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

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

19 голосов
/ 27 сентября 2008

Просто используйте необработанный указатель для вашего параметра функции вместо shared_ptr. Цель интеллектуального указателя - контролировать время жизни объекта, но время жизни объекта уже гарантировано правилами области видимости C ++: он будет существовать, по крайней мере, до конца вашей функции. То есть вызывающий код не может удалить объект до того, как ваша функция вернется; таким образом, безопасность «тупого» указателя гарантируется, если вы не пытаетесь удалить объект внутри вашей функции.

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

14 голосов
/ 27 сентября 2008

boost имеет решение для этого варианта использования, отметьте enable_shared_from_this

9 голосов
/ 27 сентября 2008

Вы действительно делаете больше общих копий pFoo внутри панели? Если вы не делаете ничего сумасшедшего внутри, просто сделайте это:


void bar(Foo &foo)
{
    // ...
}
5 голосов
/ 25 декабря 2012

С C ++ 11 shared_ptr и enable_shared_from_this теперь в стандартной библиотеке. Последнее, как следует из названия, именно для этого случая.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Пример базируется на этом в ссылках выше:

struct Good: std::enable_shared_from_this<Good>{
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

использование:

std::shared_ptr<Good> gp1(new Good);
std::shared_ptr<Good> gp2 = gp1->getptr();
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';
3 голосов
/ 27 сентября 2008

Функция, принимающая указатель, хочет выполнить одно из двух действий:

  • Имейте переданный объект и удаляйте его, когда он выходит из области видимости. В этом случае вы можете просто принять X * и сразу обернуть scoped_ptr вокруг этого объекта (в теле функции). Это сработает, чтобы принять «this» или вообще любой объект, выделенный в куче.
  • Поделиться указателем (не принадлежать ему) к передаваемому объекту. В этом случае вы не хотите вообще использовать scoped_ptr, так как вы не Я не хочу удалять объект в конце вашей функции. В этом случае, что вам теоретически нужно, так это shared_ptr (я видел, что в другом месте он называется connected_ptr). У библиотеки повышения есть версия shared_ptr , и это также рекомендуется в книге Скотта Мейерса Effective C ++ (пункт 18 в 3-м издании).

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

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