Learn Auto_Ptr Template In 8 Steps

Table Of Contents

Introduction

I have always been intrigued by the auto pointer in C++ and use it regularly; and many others could benefit from this information. This tutorial was written to the best of my knowledge after carefully scrutinized research and I hope it proves useful. Have fun reading!
[back]

What is the auto_ptr template?

The auto_ptr template is a template in the STL. It is a great resource for avoiding memory leaks when dealing with dynamically allocated memory. As you know, when memory is created on the heap with the new keyword it also has to be cleaned off the heap using the delete keyword. Many times people forget to add the delete keyword because when programs get long, it becomes difficult to keep track of the pointersor sometime person just simply forgets amidst all the other complexity. The auto_ptr template cleans up the memory for you, so that you can just create memory on the heap and not have to ever worry about the consequences. That is the auto_ptr template in a nutshell.
[back]

How do I use it? Part 1

This will help get the point accross. Here is a basic example of two programs, one using a regular pointer and the other using the auto_ptr template:

example 1 example 2

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer
	string* strVarPtr = new string;

	*strVarPtr = "Hello World";
	cout << *strVarPtr << endl;

	// deleting pointer
	delete strVarPtr;

	return EXIT_SUCCESS;
}

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory> // header for the auto_ptr
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer
	auto_ptr<string> strVarPtr(new string);

	*strVarPtr = "Hello World";
	cout << *strVarPtr << endl;

	// deleting isn't needed here

	return EXIT_SUCCESS;
}

Both programs do exactly the same thing. They both create a string pointer that points to a string object on the heap. The string object on the heap is given the value, "Hello World". Then they both stream the value of the string object to the standard output buffer (which is usually the console/shell). The only difference between the two programs is that the program on the right used the auto_ptr template to govern the pointer, while the one on the left used a regular pointer. As a result, the pointer on the right did not need the delete keyword because the auto_ptr template automatically frees the memory on the heap. (NOTE: The auto_ptr template automatically frees the memory on the heap whenever the auto pointer goes out of scope). The example on the left used a regular pointer so unfortunately it needed to delete the memory manually. See! The auto pointer makes your life so much easier!
[back]

How do I use it? Part 2

Next, lets look at how the regular pointer and the auto pointer behave when used with exceptions. This is where the auto_ptr template really shines! Proof read this coding before the explanation:

example 1 example 2

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer
	string* strVarPtr = new string;

	// given a value
	*strVarPtr = "Hello World";

	/* throws code to some imaginary
	catch block outside of main() */
	if (*strVarPtr != "foo") throw(21);

	/* deleting pointer....but wait oops!
	runtime never gets here */
	delete strVarPtr;

	return EXIT_SUCCESS;
}

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer				
	auto_ptr<string> strVarPtr(new string);

	// given a value
	*strVarPtr = "Hello World";

	/* throws code to some imaginary
	catch block outside of main() */
	if (*strVarPtr != "foo") throw(21);

	/* NOTE: even if the catch block ends the
	 * program prematurely, the auto_ptr still
	 * frees the memory anyway */

	return EXIT_SUCCESS;
}

The code above was deprecated to save some time while writing this tutorial, allow me to fill you in. Imagine that the two examples just shown to you are both pieces of two larger programs. There is a catch block in both the programs that use the C++ exit() function to end the program. Now with that in mind; here is the runtime of both programs.

In example 1, a regular pointer is created at the beginning of the program and then given a value. However, in the middle of the program an error happens and the code is thrown to the imaginary catch block. The catch block handles the error by ending the program. Therefore, the delete keyword that deletes the pointer is never reached. So a memory leak occurs.

In example 2 an alternate series of events transpire. Since the pointer was made with the auto_ptr template, when the catch block ends the program the auto_ptr still automatically frees the memory on the heap! The reason for that is because when you end programs prematurely the auto_ptr variables are forced to go out of scope, and we know what happens when an auto_ptr goes out of scope! This is the reason why using the auto_ptr template is great for exception safe code.
[back]

How do I use it? Part 3

Remember, the auto_ptr template allocates and deallocates memory for you on the heap. The object being created/destroyed is actually just a member in the template. So in other words, the address of the auto_ptr is not the same address of the object the auto_ptr creates/contains. Before you continue, stop and reread the last couple of sentences; make sure you understand that principle before you continue on. Armed with that new bit of information the next question that presents itself is, how do regular pointers get the memory address of the object an auto_ptr contains? Below illustrates two ways you can retrieve the address of the object inside of an auto_ptr template:

example 1 example 2

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer
	auto_ptr<string> strVarPtr1(new string);

	// giving value
	*strVarPtr1 = "Hello World";

	/* retrieving address of the object
	the auto_ptr contains */
	string* strVarPtr2 = strVarPtr1.get();
	
	/* showing the memory address both
	pointers point too */
	cout << strVarPtr1.get() << endl;
	cout << strVarPtr2 << endl;

	/* no delete keyword needed here because
	the auto_ptr handles the clean up */

	return EXIT_SUCCESS;
}

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating pointer
	auto_ptr<string> strVarPtr1(new string);

	// giving value
	*strVarPtr1 = "Hello World";

	/* retreiving address of the object
	the auto_ptr contains, plus taking
	ownership of the object */
	string* strVarPtr2 = strVarPtr1.release();

	/* showing the memory address both
	pointers point too */
	cout << strVarPtr1.get() << endl;
	cout << strVarPtr2 << endl;

	// this pointer has to be deleted manually
	delete strVarPtr2;

	return EXIT_SUCCESS;
}

Ok, now the explanation. The auto_ptr's get() function returns the memory address to the object that the auto_ptr contains, but the auto_ptr does not relinquish ownership of that object. So in example 1, the regular pointer called strVarPtr2 points to the same object the auto_ptr called strVarPtr1 created on the heap (thats why the output of both variables are the same). However, the auto_ptr variable still "owns" the object. So since it still owns the object, at the end of the program the auto_ptr will automatically clean the object off the heap. The regular pointer does not need to delete the object off the heap. If you did do that the object would be cleaned twice! (Note: The variable that owns the object, is the only variable that needs to delete the object from the heap.)

Now in example 2 an alternate scenario happens. The regular pointer called strVarPtr2 still receives the address of the object on the heap. However, the release() function from the auto_ptr template, returns the address of the object on the heap and releases "ownership" of that object. So since the auto_ptr doesn't own the object anymore it will not clean it from memory! The regular pointer is now the only reference to the object and it has to delete the object from the heap manually instead. That is why the output of the auto_ptr in this instance is 0 or NULL.
[back]

How do I use it? Part 4

Lets push on! This section is about reassigning auto_ptr objects. Occasionally, halfway through a program it is necessary to reassign a pointer. Lets establish something up front, a const auto_ptr cannot be reassigned or copied. Now as for variables that are not const, below shows how to reassign the auto_ptr object. Example 1 just shows the equivalent of what the auto_ptr does in example 2:

example 1(translation) example 2

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
// making pointer with the value "Hello World"
string* strVarPtr1 = new string("Hello World");

// cleaning first object, creating a new one
delete strVarPtr1;
strVarPtr1 = new string("Bye Bye World");

// showing the value
cout << *strVarPtr1 << endl;

// cleaning string object off the heap
delete strVarPtr1;

return EXIT_SUCCESS;
}

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
// making pointer with the value "Hello World"
auto_ptr<string> strVarPtr1(new string("Hello World"));

// cleaning first object, creating a new one
strVarPtr1.reset(new string("Bye Bye World"));

// showing the value
cout << *strVarPtr1 << endl;

// cleaning done automatically

return EXIT_SUCCESS;
}

The programs created one string object that said "Hello World". Next they cleaned that string object from memory and created a new string object that said "Bye Bye World". Then they print the value of the new string object to the standard output (just to prove to you a new object with a new value was created). The main thing to remember is that we destroyed the first string object, the string being written to the screen is a second string object that was created on the heap. That is what the reset() function of the auto_ptr template does, it cleans the object it previously had on the heap and then creates a new object. As you can see, doing this with the auto_ptr is much easier than using regular pointers, it takes fewer lines of code!

(NOTE: Use reset with 0 as the parameter if you want to delete the previous object without setting a new one.)
[back]

How do I use it? Part 5

This part contains a couple rules about copying auto_ptr's. If one auto_ptr is equal to another auto_ptr, what you think would happen does not happen! You would expect the auto_ptr on the left to copy the value of the auto_ptr on the right. However that is not what happens because the auto_ptr template does not make valid copies of itself. Instead of making a copy of itself, it transfers ownership of the object that the auto_ptr on the right contains. Learn by example:

example

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
	// creating two pointers, one is empty
	auto_ptr<string> strVarPtr1(new string("Hello World"));
	auto_ptr<string> strVarPtr2;

	// transferred not copied
	strVarPtr2 = strVarPtr1;

	// showing the memory address both pointers point too	
	cout << strVarPtr1.get() << endl;
	cout << strVarPtr2.get() << endl;

	return EXIT_SUCCESS;
}

What happens here is simple enough. The assignment of strVarPtr1 to strVarPtr2 does not mean they are both equivalent because the auto_ptr doesn't make valid copies of itself. Instead, the strVarPtr1 tranfers ownership to the strVarPtr2. So now the variable strVarPtr2 owns and points to the object that strVarPtr1 use to own and point too, got it? At the end of the program strVarPtr2 will clean the object from memory. The strVarPtr1 variable will not clean anything from memory because it doesn't own an object (hence the reason why the standard output shows up as 0 or NULL).

It is a great thing that the auto_ptr template works the way it does. If it did not work in this fashion then a sort of, "custody battle", would emerge between auto_ptr objects. Multiple auto_ptr's would be allowed to point to the same area of memory. Then if the variables were to go out of scope, that area of memory would be deleted multiple times!

Also remember what I mentioned earlier about constant auto_ptr's. They cannot be reassigned or copied. So if strVarPtr1 was declared with the const keyword, the compiler would throw an error because the assignment to strVarPtr2 would be illegal. The variable strVarPtr1 would not be allowed to transfer ownership because it is constant and that would change the data it holds.

Lastly, auto_ptr based objects should not be put into any data structures by rule of thumb. The reason for that is because data structures can make copies of the data internally....and that would lead to problems! So don't use the auto_ptr as an element in the STL's data structures. (NOTE: This doesn't mean you can't make an auto_ptr of the data structure itself. It just means, make sure the elements inside the structure are not auto_ptr based.)
[back]

Interlude

Thus far the only thing that I've been showing you is how the auto_ptr template is useful in the main body of a program. However, I don't want to mislead you. You can use the auto_ptr template in functions as well, and all the same rules mentioned previously apply and work in exactly the same way. The auto_ptr would automatically release the memory at the end of the function when the variable go out of scope and everything. For the remaining duration of this tutorial the focus will be on the role of the auto_ptr template when being used with functions.

Before I go on though, there is one other thing that you should know. It is something simple that I didn't think was worth dedicating an entire section too. The auto_ptr template should not be used with dynamically allocated arrays. In otherwords things resembling the syntax: auto_ptr<int> (new int[100]);. The reason for that is because the auto_ptr template cleans the memory off the heap using delete instead of delete[]. This is a limitation of the auto_ptr template, and unfortunately if a developer did write that it would still compile in many compilers. So it is just one of those things you should take note of and avoid.
[back]

How do I use it? Part 6

Ok, so in this section lets use the auto pointer to pass an argument to a function by value:

example

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

void function1(auto_ptr<string> strBufferPtr) {
	// ...code would here

	// frees strBufferPtr from off the heap
}

int main(int argc, char* argv[]) {
	/* creating pointer with the value that will 
	be put on the heap */
	auto_ptr<string> strVarPtr1(new string("Hello World"));

	// transferred not copied
	function1(strVarPtr1);

	// showing the memory address
	cout << strVarPtr1.get() << endl;

	return EXIT_SUCCESS;
}

You probably already figured out what happens here. When strVarPtr1 is given as a parameter to function1(), what really happens is: strBufferPtr = strVarPtr1;. It does not copy the data, it follows the rules we laid down previously and transfers ownership! Again, when an auto_ptr is copied it does not really get copied but instead it gets transferred. So strBufferPtr now owns the object strVarPtr1 used to own, and at the end of function1() when the variable goes out of scope the memory will be cleaned off the heap. The variable strVarPtr1 gave up ownership of the object when it was passed to function1(). So strVarPtr1's value becomes 0/NULL when function1() gets executed (hence the reason standard output prints the 0/NULL for variable strVarPtr1).

Just a tip. If a function you want to use needs a regular pointer and you are using an auto_ptr, there is a perfectly simple solution for that. Simply use auto_ptr's get() as a parameter to the function that uses a regular pointer. The auto_ptr's get() returns a regular pointer. For example: void functionNeedsRegPtr(varAutoPtr.get());.
[back]

How do I use it? Part 7

Now lets use the auto_ptr to return information from a function by value:

example

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
#include <string>
using std::auto_ptr;
using std::cout;
using std::endl;
using std::string;

auto_ptr<string> function1() {
	// creating an auto_ptr
	auto_ptr<string> strBufferPtr(new string("Hello World"));

	return strBufferPtr; // giving up ownership
}

int main(int argc, char* argv[]) {
	// making an empty pointer
	auto_ptr<string> strVarPtr1;

	// transferred not copied
	strVarPtr1 = function1();

	// showing the memory address
	cout << strVarPtr1.get() << endl;

	return EXIT_SUCCESS;
}

By now I am sure you are catching on. Variable strVarPtr1 is assigned to the return value of function1(). So what really is happening here is: strVarPtr1 = strBufferPtr;. Yep, it is just copying data again! Now as we know that really means transferring because the auto_ptr template doesn't make valid copies. So function1() creates a string on the heap, and then transfers ownership of that string object when it is returned. function1() does not clean the string object off the heap. So the variable strVarPtr1 that used to be empty, now owns that string object function1() created. So strVarPtr1 will clean it from memory when the program ends.

The other reason why returning an auto_ptr from a function is good is because it avoids a possible memory leak. If someone were to use function1() but ignored the return value instead of assigning it to a variable, a memory leak would not occur. If function1() used regular pointers to allocate the memory on the heap and ignored the return value, the memory on the heap would never be freed and a memory leak would occur.
[back]

How do I use it? Part 8

Lastly, lets examine how the auto_ptr template can be useful when writing a class:

example

#include <cstdlib>
#include <ostream>
#include <iostream>
#include <memory>
using std::auto_ptr;
using std::cout;
using std::endl;

class SimpleObject {
	public:
		SimpleObject(int intBuffer): intVarPtr(new int(intBuffer)) { }
		~SimpleObject()
			{
				// no delete keyword needed
			}
		void showNumber() const
			{
				cout << *intVarPtr << endl;
			}

	private:
		auto_ptr<int> intVarPtr;
};

int main(int argc, char* argv[]) {
	/* creating local SimpleObject, which
	holds the value of 50 on the heap */
	SimpleObject MySimpleObject(50);

	// showing the value
	MySimpleObject.showNumber();

	return EXIT_SUCCESS;
}

Here there is a class called SimpleObject. The program creates a SimpleObject on the stack. The integer member that SimpleObject has is created on the heap. When the program ends that integer is automatically taken off the heap by SimpleObject because it was made using the auto_ptr template. If SimpleObject had used regular pointers to put the integer on the heap, a delete keyword would be needed in it's deconstructor. Once again the auto_ptr accomplishes the same task in fewer lines!

Just a tip. I wrote this section just because the tutorial would not be complete without it. But putting things on the heap in this manner is a lot of unneeded work. Instead of declaring members on the heap in a class, it would be much easier to make all the class members local. Then just declare the object itself on the heap.
[back]

Conclusion

Use the auto_ptr more often whenever you can because it will avoid memory leaks in your programs. Do however keep in mind that the main limitations of the auto_ptr template is that it cannot be copied and it cannot handle arrays of data. By the way, the auto_ptr template is in a category of pointers called "smart pointers". There are a lot of smart pointers available to C++ programmers. Many people have created their own custom templates for smart pointing, some of them are free some of them are not. The one in the STL however is a free one. I suggest you familiarize yourself with the smart pointers in the Boost library if you plan to further pursue smart pointers. I sincerely hope you enjoyed the article. I tried to make it as small and concise as possible, but it was a lot of information to compact. Oh yeah! By the way, feedback is always welcome!
[back]

Works Cited

[back]


Created By: Alwyn Malachi Berkeley Jr.
Created: 04-12-06
Last Modified: 11-08-10
Send questions and comments to coding at youngcoder.com