Вопросы по использованию shared ptr-c++

у меня есть несколько вопросов о наилучшей практике использования shared_ptr.

Вопрос 1

копирование shared_ptr дешевые? Или мне нужно передать его как ссылку на мои собственные вспомогательные функции и возвращать как значение? Что-то вроде

void init_fields(boost::shared_ptr<foo>& /*p_foo*/);
void init_other_fields(boost::shared_ptr<foo>& /*p_foo*/);

boost::shared_ptr<foo> create_foo()
{
    boost::shared_ptr<foo> p_foo(new foo);
    init_fields(p_foo);
    init_other_fields(p_foo);
}

Вопрос 2

должен ли я использовать boost::make_shared построить shared_ptr? Если да, то какие преимущества он дает? И как мы можем использовать make_shared, когда T нет конструктор без параметров?

Вопрос 3

как использовать const foo*? Для этого я нашел два подхода.

void take_const_foo(const foo* pfoo)
{

}

int main()
{
    boost::shared_ptr<foo> pfoo(new foo);
    take_const_foo(pfoo.get());
    return 0;
}

или

typedef boost::shared_ptr<foo> p_foo;
typedef const boost::shared_ptr<const foo> const_p_foo;

void take_const_foo(const_p_foo pfoo)
{

}

int main()
{
     boost::shared_ptr<foo> pfoo(new foo);
     take_const_foo(pfoo);
     return 0;
}

Вопрос 4

как я могу вернуться и проверить для NULL на

5 ответов


на большинство вопросов были даны ответы, но я не согласен с тем, что копия shared_ptr дешева.

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

с точки зрения производительности, это гораздо лучше чтобы использовать контейнер указателя boost вместо контейнера shared_ptr.


  1. копирование дешево, указатель не занимает много места. Весь смысл в том, чтобы сделать его маленьким, чтобы разрешить использование в контейнерах по значению (например,std::vector< shared_ptr<Foo> > ).

  2. make_shared принимает переменное количество параметров, и является предпочтительным mechanicsm над созданием его самостоятельно (просто как make_pair). Преимуществом является читаемость, особенно если задействованы временные и/или пространства имен:

  3. boost:: const_ptr_cast как уже предлагалось

  4. интеллектуальные указатели имеют перегруженные операторы и могут непосредственно использоваться в выражениях, вычисляемых для bool. Не используйте get. За что угодно. Вместо сравнения p.get ни к чему, сравните пустой экземпляр указателя (my_ptr != boost::shared_ptr< MyClass >() )

объявление.2

func_shared( boost::shared_ptr<my_tools::MyLongNamedClass>( 
    new my_tools::MyLongNamedClass( param1, param2 ) );

и

func_shared( boost::make_shared<my_tools::MyLongNamedClass>( param1, param2 ));

  1. да, копия абсолютно дешевая. Помимо удержания указателя, есть (обычно) еще один член данных для класса shared_ptr - счетчик использования.
  2. Не могу ответить на этот вопрос, я обычно использую версии boost до появления make_shared (1.40?)
  3. используйте boost:: const_pointer_cast
  4. shared_ptr есть оператор==/!= определенный. В приведенном выше примере: if (f)

  1. копирование shared_ptr теперь стоит 32 байта в копии стека и дополнительных приращениях/уменьшениях refcount. Решите, дешево ли это для вас или нет, но я не вижу причин, почему бы не передать ссылку const, тем более, что у вас уже есть typedef для ptr: void f(const foo_ptr &myfoo) особенно учитывая, что стандартный параметр no-write-permissions, передаваемый в C++, является ссылкой const.

  2. Я бы предпочел не иметь функций, которые принимают указатель, который не является общим. Это похоже (хотя и не идентично) на семантику передачи параметров в Java и C#. Зачем погружаться в решение каждый раз, как передать объект, вместо того, чтобы иметь один стандартный способ сделать это?

  3. использовать if(p) как и для обычных указателей. Семантика преобразования boolean довольно аккуратна.


  1. одна из основных причин существования shared_ptr должна быть относительно дешевой для копирования.
  2. существуют версии make_shared, которые принимают параметры (и если ваш компилятор поддерживает variadic шаблоны, тот, который принимает список переменных параметров).
  3. похоже, вы ищете const_ptr_cast?
  4. чтобы вернуть нулевой указатель, вы можете передать' 0 ' в share_ptr ctor. Для проверки на нулевой указатель, можно сравнить С. получить() в 0.