Вопросы по использованию shared_ptr - C ++ - PullRequest
17 голосов
/ 27 января 2010

У меня есть несколько вопросов о лучших практиках использования 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;
}

OR

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 на shared_ptr объекте? Это что-то вроде

boost::shared_ptr<foo> get_foo()
{
     boost::shared_ptr<foo> null_foo;
     return null_foo;
}

int main()
{
     boost::shared_ptr<foo> f = get_foo();
     if(f == NULL)
     {
          /* .. */
     }
     return 0;
}

Любая помощь будет отличной.

Ответы [ 5 ]

8 голосов
/ 27 января 2010

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

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

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

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

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

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

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

AD.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 ));
3 голосов
/ 27 января 2010
  1. Копирование shared_ptr теперь стоит 32 байта при копировании стека и дополнительных приращений / уменьшений повторного счета. Решите, дешево это для вас или нет, но я не вижу причин, почему бы не передать константную ссылку, особенно если у вас уже есть typedef для ptr: void f(const foo_ptr &myfoo) особенно учитывая, что стандартная передача параметров no-write-permissions в C ++ является константной ссылкой.

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

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

3 голосов
/ 27 января 2010
  1. Да, копия абсолютно дешевая. Помимо удержания указателя, есть (обычно) еще один элемент данных для класса shared_ptr - количество использования
  2. Использовать boost :: const_pointer_cast
  3. shared_ptr имеет оператор == /! = Определен. В вашем примере выше: if (f)
2 голосов
/ 27 января 2010
  1. Одна из основных причин существования shared_ptr - сравнительно дешевое копирование.
  2. Существуют версии make_shared, которые принимают параметры (и, если ваш компилятор поддерживает шаблоны с переменным числом аргументов, тот, который принимает список переменных параметров).
  3. Похоже, вы ищете const_ptr_cast?
  4. Чтобы вернуть нулевой указатель, вы можете передать '0' в ctor share_ptr. Чтобы проверить нулевой указатель, вы можете сравнить p.get () с 0.
...