Вопросы об использовании shared_ptr - С++
У меня мало вопросов о лучших методах использования 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
на объект 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;
}
Любая помощь будет отличной.
Ответы
Ответ 1
На большинство вопросов был дан ответ, но я не согласен с тем, что копия shared_ptr дешева.
Копия имеет различную семантику из пошаговой ссылки. Он изменит счетчик ссылок, который вызовет атомный приращение в лучшем случае и блокировку в худшем случае.
Вы должны решить, какую семантику вам нужно, и тогда вы узнаете, следует ли передавать по ссылке или по значению.
С точки зрения производительности обычно лучше использовать контейнер указателя ускорения вместо контейнера shared_ptr.
Ответ 2
-
Копирование дешево, указатель не занимает много места. Все дело в том, чтобы сделать его маленьким, чтобы разрешить использование в контейнерах по значению (например, std::vector< shared_ptr<Foo> >
).
-
make_shared
принимает переменное количество параметров и является предпочтительной механикой над ее построением (точно так же, как make_pair
). Преимущество - читаемость, особенно если задействованы временные и/или пространства имен:
-
boost:: const_ptr_cast как уже было предложено
-
интеллектуальные указатели имеют перегруженные операторы и могут быть непосредственно использованы в выражениях, оцененных как 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
- Да, копия абсолютно дешевая. Помимо удержания указателя, есть (обычно) еще один член данных для класса shared_ptr - счет использования.
- Не могу ответить на это, я обычно использую boost-версии до того, как был введен make_shared (1.40?)
- Использовать boost:: const_pointer_cast
- shared_ptr имеет оператор ==/!= определенный. В приведенном выше примере: if (f)
Ответ 4
-
Копирование shared_ptr теперь стоит 32 байта в копии стека и дополнительных приращениях/сокращениях refcount. Решите, дешево ли это для вас или нет, но я не вижу причин, почему бы не передать ссылку на const, особенно, что у вас уже есть typedef для ptr:
void f(const foo_ptr &myfoo)
особенно учитывая, что стандартный параметр разрешения отсутствия записи-записи в С++ является ссылкой на константу.
-
Я бы предпочел не иметь никаких функций, которые принимают указатель, который не является общим. Это похоже (хотя и не идентично) семантике передачи параметров в Java и С#. Почему нужно каждый раз решать, как передать объект, а не иметь один стандартный способ его выполнения?
-
Используйте if(p)
так же, как для обычных указателей. Булева семантика преобразования довольно аккуратная.
Ответ 5
- Одной из основных причин существования shared_ptr является относительно дешевая копия.
- Существуют версии make_shared, которые принимают параметры (и если ваш компилятор поддерживает Variadic templates, тот, который принимает список переменных).
- Похоже, вы ищете const_ptr_cast?
- Чтобы вернуть нулевой указатель, вы можете передать '0' в share_ptr ctor. Чтобы проверить нулевой указатель, вы можете сравнить p.get() с 0.