2
\$\begingroup\$

I know I haven't implemented many methods, and haven't specialized it for T[], but I just want to see if what I coded is good or bad.

template< class T >
class unique_ptr
{
private:
   T* ptr;
   
public:
   unique_ptr() noexcept : ptr(nullptr) {}
   ~unique_ptr() noexcept { release(); }
   explicit unique_ptr(T* data) noexcept;
   unique_ptr(const unique_ptr& rhs) = delete;
   unique_ptr& operator=(const unique_ptr& rhs) = delete;
   unique_ptr(unique_ptr&& rhs) noexcept;
   unique_ptr& operator=(unique_ptr&& rhs) noexcept
   {
       ptr = std::move(rhs.ptr);
   }
   T& operator*() { return *get(); }
   T* get() const noexcept;
   T* release() noexcept;
};

template< class T >
unique_ptr<T>::unique_ptr(T* data) noexcept : ptr(data) {}
template< class T >
unique_ptr<T>::unique_ptr(unique_ptr&& rhs) noexcept
{
   ptr = std::move(rhs.ptr);
}
template< class T >
T* unique_ptr<T>::get() const noexcept
{
   return ptr;
}

template < class T >
T* unique_ptr<T>::release() noexcept
{
   auto old_ptr = ptr;
   ptr = nullptr;
   return old_ptr;
}

template< typename T, typename ...Args >
unique_ptr<T> make_unique(Args&&... args)
{
   return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

What's implemented so far looks mostly fine, except for the destructor. I would add operator->() as soon as possible, since we have operator*() - they come as a pair, and I don't think it's yet defaultable in the way that != can be synthesized when we provide ==.

Technically, we don't need = delete declarations of copy-construct/assign, since providing move-construct/assign inhibits those. But I like showing that explicitly - it can help the reader.

We could make the T* constructor also be the default constructor, by using a default argument:

   explicit unique_ptr(T* data = nullptr) noexcept;

operator* needs to be const (it can be noexcept, too).

release() can be simplified to just return std::exchange(ptr, nullptr);. It probably should make marked [[nodiscard]] since it transfers ownership of the pointer.

There's a bug in the destructor: we just call release(), abandoning the ownership of the pointer. But we actually need to free the owned object instead:

   ~unique_ptr() noexcept { delete ptr; }

(Remember that delete on a null pointer is safe, and does nothing).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.