Ask the C++ Pro 10-Minute Solutions

Using the auto_ptr Class Template to Facilitate Dynamic Memory Management
By Danny Kalev

Dynamic memory appears to be the most widely-used resource in C++ applications. Although well-disciplined programmers know that every invocation of operator new must be followed by a matching delete, under some circumstances memory leaks may still occur. When exceptions are thrown, the program's normal flow of control is diverted, thereby causing potential memory leaks. For example:

void g() //might throw
    if (some_condition == false)
      throw X();
  void func() 
    string * pstr = new string;
    g(); //memory leak if g throws an exception
    delete pstr; //unreachable code if g() throws
  int main()
When g() throws an exception, the exception-handling mechanism unwinds the stack: g() exits and control is transferred to the catch(...) block in main(). However, the delete statement in func() is not executed, and as a result, the memory owned by pstr leaks. Had we used a local automatic string object—rather than a dynamically allocated one—the leak would have been avoided:

    string  str; //local automatic object
    g(); //no memory leaks
Still, many nontrivial data models and applications such as linked lists, STL containers, strings, database systems, and interactive applications must allocate memory dynamically, taking the risk of causing memory leaks in case of exceptions. The C++ Standardization committee was aware of this loophole and added a special class template to the Standard Library, namely std::auto_ptr, whose purpose is to smoothen the interaction between dynamic memory and exceptions. Auto_ptr ensures that objects allocated on the free store (i.e., objects allocated by operator new) are automatically destroyed and their memory is released when an exception is thrown. The following sections explain how to use auto_ptr effectively and correctly to avoid resource leaks. The discussion here focuses on dynamic memory. However, this technique is applicable to files, threads, locks, and similar resources.

Auto_ptr is defined in the header <memory>. Like every other member of the Standard Library, it is declared in namespace std::. When you instantiate an auto_ptr object, you initialize it with a pointer to a dynamically allocated object like this:

#include <memory>
  #include <string>
  using namespace std;
  void func()
    auto_ptr<string> pstr (new string); /* create and 
	initialize an auto_ptr */
In the angle brackets, you specify the type of the object to which the auto_ptr points, string in this example. Following that is the name of the auto_ptr instance, pstr in this example. You initialize the instance with a pointer to a dynamically allocated object. Note that you can only use auto_ptr's copy constructor for that purpose. The following, on the other hand, is illegal:

auto_ptr<string> pstr  = new string; //compilation error
Auto_ptr is a template. Therefore, it's completely generic. It can point to any type of object, including fundamental types:

auto_ptr<int> pi  (new int);  
Once you have instantiated an auto_ptr and initialized it with the address of a dynamically allocated object, you use it as if it were an ordinary pointer to that object:

*pstr = "hello world"; //dereference and assign
  pstr->size(); //call a member function
This is possible because auto_ptr overloads the operators &, * and ->. Don't let the syntax mislead you, though: pstr is an object, not a pointer.

How does auto_ptr solve the memory leak problem that we previously saw? The destructor of auto_ptr automatically destroys the dynamically allocated object bound to it. In other words, when the destructor of pstr executes, it deletes the pointer to string that was created during pstr's construction. You must never delete an auto_ptr since it is a local object, and as such, its destructor is invoked automatically. Let's look at a revised version of func() that uses auto_ptr:

void func() 
    auto_ptr<string>  pstr (new string);
    g();  //pstr is destroyed automatically if g() throws 
C++ guarantees that objects with automatic storage type are destroyed during the stack unwinding process. Therefore, if g() throws an exception, the destructor of pstr will execute before control is transferred to the catch(...) block in main(). Now, since pstr's destructor deletes the pointer to string to which it is bound, no memory leaks occur. To conclude, auto_ptr provides the automation and safety of a local object when using a dynamically allocated object.

As convenient as auto_ptr may seem, there are some pitfalls that you should avoid when using it. First, never use auto_ptr objects as elements of STL containers. The C++ Standard explicitly forbids this and you may encounter undefined behavior (for reasons that we will not discuss here).

Another common pitfall is using an array as an auto_ptr argument:

auto_ptr<char>  pstr (new char[12] ); //array; undefined
Remember that whenever you're using array-new, you need to use delete [] to properly destroy that array. However, auto_ptr's destructor invokes only non-array delete. Consequently, the array is not properly destroyed and the program's behavior is undefined. To summarize, auto_ptr should only hold a pointer to a single object that was allocated by new.

Other 10-Minute Solutions
 How to Change the Mouse Pointer without Flicker
 Setting Full Row Selection in ListView Control
 Automating Type Conversions with stringstream Objects
 Improving Memory Reallocation with Vectors
 How to Use <fstream> Classes for File I/O
 Casting About for Safe Typecasting
 Overloading Operator + the Right Way
 How to Create Persistent Objects
 Making Linked Lists More User-Friendly
 Preventing Glitches in Signal Processing
 Forcing Object Allocation on the Free-store
 Using String-Based Data Validation
 Implementing the 'Resource Acquisition Is Initialization' Idiom
 Simple Locks for Data Files
 Template Specializations
 Exception Handling
 Using Bit Fields in Data Optimization
 Using the Transform() Algorithm to Change a String's Case
 Use RTTI for Dynamic Type Identification
 Choosing the Right swap () Implementation
 Take Charge and Initialize Your Own Data
 Share Data Among Objects Using the Monostate Design Pattern
 String Manipulation Made Easy with std::string Algorithms
 Using typedef to Curb Miscreant Code
 Managing Objects' Construction Order
 Bitwise Operators: Combining Efficiency and Ease of Use
 Use Function Adapters to Extend Generic Algorithms' Usage
 Simplify Callback Dispatching with Enumerated Indexes
 Streamline Your Bulk I/O Operations with Stream Iterators
 Optimize Your Member Layout
 Preserve Code Safety with Conversion Operators
 Modify Your Base Class Interface in Derived Classes
 Tackle Common Programming Tasks Using the New <tuple> Library
 Use Local Classes for Proper Cleanup in Exception-enabled Apps
 Use multimap to Create Associative Containers with Duplicate Keys
 Enforcing Compile-time Constraints
 Facilitate Directory Operations with the <dirent.h> and <dir.h> Libraries
 Spruce Up Your Built-in Arrays
 Target 32- and 64-bit Platforms Together with a Few Simple Datatype Changes
 Restrict Object Allocation to Specific Memory Types
 Use the Pimpl Idiom to Reduce Compilation Time and Enhance Encapsulation
 Automate Resource Management with shared_ptr
 The Quick and Dirty Way to Add
 Pointing to Class Members
 Detecting Keystrokes While Your Application is Busy
 Linked Lists
 Programming the System Tray
 Create a "Universal" DLL
 Convert Path to Long Path Name
 Constructing an Object at a Pre-Determined Memory Position
 Declaring Classes and Member Functions in a Namespace
 Using the auto_ptr Class Template to Facilitate Dynamic Memory Management
 Using the random_shuffle() Algorithm to Randomize a Sequence of Elements
 Defining a Function Object
 Implementing the Singleton Design Pattern
 Declaring Function Pointers and Implementing Callbacks
 Overloading Operator << for a User-Defined Type
 Implementing a Stopwatch Class for Performance Measurements
 Creating and Accessing Environment Variables
 Executing an Object's Member Function in a Separate Thread
 Creating Heterogeneous Containers
 Overriding New and Delete
 Time and Date Manipulation
  Defining Functions with a Variable Argument List
 Optimize Abstract Operations with Function Templates

Ask the C++ Pro | Who is the Pro? | Usage Policies | Search | Feedback

Sponsored Links

Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks


Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers