Boost shared_ptr: разница между operator = и reset?
Существуют ли какие-либо различия между двумя фрагментами кода ниже? Кто-нибудь из них предпочтительнее другого?
оператор =
boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo = boost::shared_ptr<Blah>(new Blah()); // Involves creation and copy of a shared_ptr?
reset
boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo.reset(new Blah()); // foo.ptr should point now to a new Blah object
Примечание. Мне нужно определить shared_ptr, а затем установить его в другой строке, потому что я использую его в фрагменте кода, например:
boost::shared_ptr<Blah> foo;
try
{
foo.reset...
}
foo...
Ответы
Ответ 1
operator=
присваивает shared_ptr
a shared_ptr
, а reset
делает shared_ptr
владением указателем. Таким образом, в основном нет разницы между приведенными вами примерами. Тем не менее, вы не должны использовать никого из них и просто используйте make_shared
:
foo = boost::make_shared<Blah>();
Кроме того, если это возможно, вы можете запретить объявлять shared_ptr
без инициализации, упаковывая блок try-catch в отдельную функцию, которая просто возвращает shared_ptr
для вновь созданного объекта:
boost::shared_ptr<Blah> createBlah() {
try {
// do stuff
return newBlah;
}
catch ...
}
Ответ 2
operator=
принимает в качестве параметра другой shared_ptr
, создавая, таким образом, другую копию (и увеличивая счетчик ссылок), в то время как reset()
принимает указатель и, необязательно, дебетер, таким образом, на самом деле создает новый shared_ptr поверх текущего.
reset эквивалентен (и, вероятно, реализован как)
void reset(T p, D d)
{
shared_ptr shared(p,d);
swap( shared );
}
operator=
, скорее всего, будет реализован как:
shared_ptr& operator=( shared_ptr const& other )
{
shared_ptr shared(other);
swap(other);
return *this;
}
Две функции аналогичны тем, что они освобождают контроль над тем, что они уже содержат, если таковые имеются, и управляют другим указателем.
Ответ 3
foo.reset(p)
определяется как эквивалентный shared_ptr(p).swap(foo)
.
Назначение логически эквивалентно copy-and-swap и, возможно, реализовано таким образом. Итак, foo = shared_ptr(p);
эквивалентно foo.swap(shared_ptr(p))
. Возможно, с дополнительной копией там, если у компилятора очень плохой день.
Итак, в примерах, которые вы даете, я не думаю, что их можно выбирать между ними. Могут быть и другие случаи, когда это имеет значение. Но reset делает тот же шаблонный захват статического типа p
, который делает конструктор шаблона, так как это касается правильного делетера, вас охватывает.
Основное назначение задания - это когда вы хотите скопировать ранее существовавший shared_ptr
, чтобы передать право собственности на один и тот же объект. Конечно, он отлично работает при назначении из временного тоже, и если вы посмотрите на разные перегрузки reset
, они отражают разные конструкторы. Поэтому я подозреваю, что вы можете достичь одинаковых вещей в любом случае.
Ответ 4
Оператор присваивания создает новый общий объект из существующего, увеличивая количество ссылок
CSharedObj& CSharedObj::operator=(CSharedObj& r) noexcept
{
if(*this != r){
//detach from the previous ownership
if(0 == dec()) delete m_pControlObj;
//attach to the new control object and increment the reference count
r.inc();
m_pControlObj = r.m_pControlObj;
}
return *this;
}
в то время как вызов reset не создает новый общий объект, а скорее новое право собственности - присоединение к новому базовому указателю (через объект управления)
void CSharedObj::reset(Ptr pointee) noexcept
{
//check if this is a last reference-detach from the previous ownership
if(0==dec()) delete m_pControlObj;
// create the ownership over the new pointee (refCnt = 1)
m_pControlObj = new (std::nothrow) CControlObj(pointee);
}