Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a bad habit to initialize a unique_ptr using reset?

When I need to have a data member which is a type of std::unique_ptr<A>, then I have usually used std::unique::reset() to initialize this unique_ptr with a new object.

The following is a simplified example:

class A {
 public:
  void SetValue(int x) {
    data_.reset(new B(x));
  }

 private:
  std::unique_ptr<B> data_;
};

In the code review, one reviewer mentioned that it is a bad habit and he asked me not to use reset() if possible. Instead, he suggested to use the following methods:

std::make_unique

or a template function like the following:

template <typename T>
struct MakeUniqueResult {
  using scalar = std::unique_ptr<T>;
};
template <typename T, typename... Args>
typename internal::MakeUniqueResult<T>::scalar
MakeUnique(Args&&... args) {  
  return std::unique_ptr<T>(
      new T(std::forward<Args>(args)...));  
}

Are there some special reasons to avoid using std::unique_ptr::reset() in the above case?

like image 666
chanwcom Avatar asked Dec 10 '15 20:12

chanwcom


People also ask

What does unique_ptr Reset do?

unique_ptr::resetReplaces the managed object. 1) Given current_ptr , the pointer that was managed by *this, performs the following actions, in this order: Saves a copy of the current pointer old_ptr = current_ptr. Overwrites the current pointer with the argument current_ptr = ptr.

When should we use unique_ptr?

When to use unique_ptr? Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another.

What happens when unique_ptr goes out of scope?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.


1 Answers

In your example, the effect is the same whether you use std::make_unique or std::unique_ptr::reset with new.

But in more interesting code, using std::make_unique solves some exception safety issues, and that's why your code reviewer is suggesting to make it a habit.

Consider what happens if you try to create two unique pointers at once:

Frobnicate(std::unique_ptr<Foo>(new Foo), std::unique_ptr<Bar>(new Bar(3)));

The compiler has to do a bunch of work to create those two parameters, and it has a lot of flexibility in the order it can do that work. If one of the constructors throws an exception, the memory allocated for the other one may or may not be cleaned up.

But if you use std::make_unique:

Frobnicate(std::make_unique<Foo>(), std::make_unique<Bar>(3));

The temporary unique_ptrs will immediately own their respective objects and thus be able to clean them up if creating the other one throws an exception.

For exception safety, and the general guideline of avoiding using new and delete directly, it's a good habit to use std::make_unique every time.

like image 96
Adrian McCarthy Avatar answered Oct 07 '22 18:10

Adrian McCarthy