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);
}