Получаем повышение::shared_ptr для этого

Я широко использую 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 ответов

Решение

Вы можете наследовать от 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 () вместо этого. Это гарантирует, что объект не будет освобожден.

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

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

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

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


void bar(Foo &foo)
{
    // ...
}

С С ++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';

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

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

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

Другие вопросы по тегам