Using unique_ptr instead of auto_ptr

I’ve had a bit of a blogging hiatus and hope to make amends for that. Going forward, I will continue to blog on modern C++ features and also focus on newer frameworks from Microsoft (primarily C++ focused, but non-C++ technologies that interest me will also be discussed).

For years, we’ve all used auto_ptr with all its pitfalls. A minor issue was its lack of support for an array of objects, so if you used it with with an array of objects, only the first one would get deleted. A much bigger issue is that the auto_ptr transfers ownership when it’s assigned to another auto_ptr. And because this happens in a non-obvious fashion, it’s fairly easy to introduce problems in your code. The unique_ptr solves both these problems. It has a partial specialization that correctly calls delete[] on an array of objects. It also emphasizes the point of unique ownership. So you have to explicitly move an unique_ptr into another unique_ptr.

Here are some code snippets that show this more clearly.

class NumberStore
{
  int _num;

public:
  NumberStore(int num = 0) : _num(num)
  { 
    cout << "NumberStore ctor" << endl;
  }

  ~NumberStore()
  {
    cout << "NumberStore dtor" << endl;
  }

  int Num()
  {
    return _num;
  }
};

void Foo(auto_ptr<NumberStore> number)
{
  cout << "Foo : " << number->Num() << endl;
}

void AutoPtrProblem()
{
  auto_ptr<NumberStore> number(new NumberStore(100));
  Foo(number);
  Foo(number); //This call will crash
}

The 2nd call to Foo(...) will crash because the object has already been destroyed. Now consider the unique_ptr version.

void Foo(unique_ptr<NumberStore> number)
{
  cout << "Foo : " << number->Num() << endl;
}

void UniquePtrVersion()
{
  unique_ptr<NumberStore> number(new NumberStore(100));
  // Foo(number); <-- This won't compile
  Foo(move(number));
  Foo(move(number)); //This is an obvious programmer error now
}

By forcing you to explicitly call move, the compiler makes it obvious that a transfer of ownership is happening there. It’ll take some conscious bad programming to create a similar crash as before. As for an array of objects, the following method will call the destructor thrice.

void UniquePtrArrayVersion()
{
  unique_ptr<NumberStore[]> number(new NumberStore[3]);
}

So, going forward if you think you have a need for a single-owner smart pointer class, unique_ptr is the one to use, not auto_ptr. For other situations, you still do not use auto_ptr, instead you’d use shared_ptr which I’ll be blogging about shortly.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s