unique_ptr and nullptr for C++03

(I’ve been using C++ a bunch lately, so the next several posts will probably be pretty C++-centric.)

unique_ptr is the future. And the future is now! Start using unique_ptr today with this little gem, a C++03-compatible implementation. Of course, you get fancy new C++0x move semantics, pioneered by auto_ptr, but now safer, saner, more widely usable (e.g. in containers), etc. unique_ptr also supports arrays without a separate unique_array class: unique_ptr<T[]> is template-specialized. (I won’t spend this post describing unique_ptr; the provided links already do a much better job at that.)

Some more opinion from the C++03-compatible unique_ptr page:

A const unique_ptr may be considered a better scoped_ptr than even boost::scoped_ptr. The only way to transfer ownership away from a const unique_ptr is by using const_cast. Unlike scoped_ptr, you can’t even swap const unique_ptr’s. The overhead is the same (if using the default_delete or an empty custom deleter – sizeof(unique_ptr<T>) == sizeof(scoped_ptr<T>)). And custom deleters are not even a possibility with scoped_ptr.

(Note BTW that boost::interprocess::unique_ptr is not the same as the C++0x unique_ptr.)

In general, you can already achieve move semantics without rvalue-references, just by using const_cast (or mutable). This is indeed how this unique_ptr implementation works. The core idea illustrated:

template<typename T>
class moveable_ptr {
  T *p;

  // Disable copying from lvalues.
  moveable_ptr(moveable_ptr<T> &o) : p(nullptr) {}

public:
  moveable_ptr(T *p) : p(p) {}

  // In C++0x:
  // moveable_ptr(moveable_ptr<T> &&o) : p(o.p) {
  //   o.p = nullptr;
  // }

  // In C++03, settle with:
  moveable_ptr(const moveable_ptr<T> &o) : p(o.p) {
    const_cast<T*>(o.p) = nullptr;
  }

  ~moveable_ptr() { if (p) delete p; }
  T *get() const { return p; }
  ...
};

Notice above that I use nullptr instead of 0 or NULL—that’s another C++0x feature you can begin using right away, and without any hackery at all.

These goodies are all collected in my growing C++ Commons library.

Follow me on Twitter for stuff far more interesting than what I blog.

  • I don't think the signatures you've got for moveable_ptr are right. The move constructor needs to take a moveable_ptr, not a T. Oh, and you need something to prevent copying from lvalues, which you haven't shown there.

  • yaaang

    Thanks, Dave — should've checked the blog post more carefully.

  • wow got confused, what's this about guys?