Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) std::auto_ptr

 

The class template std::auto_ptr is deprecated [5]. The class template std::unique_ptr provides a better solution [5].

 

std::auto_ptr is a smart pointer that deletes the instance it points to when going out of scope. It is supplied in the STL header file memory.h.

 

std::auto_ptr helps to:

 

 

Note: when you use a lot of forward declarations, you might want to prefer boost::scoped_ptr as it uses boost::checked_delete. Also, boost::scoped_ptr cannot be copied, so you will nearly ever be amazed by 'strange' behaviour.

 

 

 

 

 

Managing pointers and preventing memory leaks

 

Standard pointer:

 

struct MyClass {};

int main()
{
  const MyClass const * p = new MyClass;
  p->doStuff();
  delete p;
}

 

Using an auto_ptr:

 

#include <memory>

struct MyClass {};

int main()
{
  const std::auto_ptr<MyClass> p(new MyClass);
  p->doStuff(); //Hey, the same way of accessing the pointed instance!
  //Done, std::auto_ptr deletes itself when going out of scope
}

 

Use objects to manage resources (like dynamically allocated memory)[2] and store newed objects in smart pointers in standalone statements [3].

 

std::auto_ptr's does more then saving you a delete statement. It ensures that the instance pointed to is only pointed to once. This is done by a non-symettric copy: when you pass a pointer from std::auto_ptr to std::auto_ptr, the original possessor gets zero. This is demonstrated below:

 

#include <memory>
#include <cassert>

struct MyClass {};

int main()
{
  const std::auto_ptr<MyClass> p1(new MyClass);
  const std::auto_ptr<MyClass> p2;

  assert(p1 != 0);
  assert(p2 == 0);

  p2 = p1; //Copies the MyClass*

  assert(p1 == 0);
  assert(p2 != 0);
}

 

To get a copy to the pointed instance use the std::auto_ptr<T>::get member function:

 

#include <cassert>
#include <memory>

struct MyClass {};

int main()
{
  const std::auto_ptr<MyClass> p1(new MyClass);
  const MyClass * const p2 = pClass.get();

  assert(p1 !=0);
  assert(p2 !=0);
}

 

 

 

 

 

Pointer management

 

Also, using a std::auto_ptr, it gets clear which class manages the deletion of the pointed instance.

 

class Something{};

struct MyClass
{
  //Ownership remains at MyClass (*)
  const Something * const GetSomethingCopy() const
  {
    return mpSomething.get();
  }

  //Ownership transferred to caller
  const std::auto_ptr<Something> GetSomething() //Cannot be a const-method!
  {
    return mpSomething;
  }

  private:

  std::auto_ptr<Something> mpSomething;
};

// (*) Note that despite the constness, the pointer can be deleted by the caller,
// without taking proper precautions (See Exercise #1: a foolproof function)

 

If the instance pointed to needs to be give to another class, then MyClass::GetSomething is left with an empty (that is: 0) pSomething.

 

 

 

 

 

Make code exception safe

 

When you create a new instance dynamically in a certain function using a plain pointer, in the end of this function you call delete. But when in the middle an exception is thrown, this delete is not called anymore! When using an auto_ptr, the instance DOES get deleted. This is because auto_ptr's delete their instances when they go out of scope.

 

 

 

 

 

Note, warnings, curiosities

 

 

 

 

 

Do not create an array dynamically using a std::auto_ptr

 

This will give you a memory leak, as a std::auto_ptr calls delete, instead of delete[]. As advised by [1], you should prefer a std::vector over an array. But if you really want to use a smart pointer, use a boost::scoped_array.

 

 

 

 

 

Do not put std::auto_ptr's in a std::vector [4]

 

A copy of a std::auto_ptr does not copy the memory address pointed to. Therefore, when using e.g. a sorting algorithm, some pointed instances might get deleted! Instead, use a boost::shared_ptr.

 

 

 

 

 

Resetting astd::auto_ptr

 

Resetting a std::auto_ptr first constructs a new instance of the class before deleting the old instance. This is demonstrated by the code below:

 

#include <iostream>
#include <memory>

struct Resetter
{
  Resetter() { std::cout << "Constructor" << std::endl; }
  ~Resetter() { std::cout << "Destructor" << std::endl; }
};

int main()
{
  std::auto_ptr<Resetter> pReset(new Resetter);
  pReset.reset(new Resetter);
}

 

This gives the following output:

 

Constructor
Constructor
Destructor
Destructor

 

The reason for this behavior is I guess- exception safety: if the allocation of the new resources fail, then the old resources are not yet released.

 

 

 

 

 

References

 

  1. Herb Sutter and Andrei Alexandrescu. C++ coding standards: 101 rules, guidelines, and best practices. ISBN: 0-32-111358-6. 2004. Chapter 77: 'Use vector and string instead of arrays'
  2. Scott Meyers. Effective C++ (3rd edition). ISBN:0-321-33487-6. 2005. Item 13: 'Use objects to manage resources'
  3. Scott Meyers. Effective C++ (3rd edition). ISBN:0-321-33487-6. 2005. Item 17: 'Store newed objects in smart pointers in standalone statements'
  4. Scott Meyers. Effective STL. ISBN:0-201-74962-9. 2001. Item 8: 'Never create containers of auto_ptr's'
  5. Working Draft, Standard for Programming Language C++. 2014-08-22. N3936. Paragraph D.10. 'The class template auto_ptr is deprecated [Note: the class template unique_ptr provides a better solution -end note]'

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict