In a previous post I suggested that raw pointers should be replaced by smart pointers. This post explains why smart pointers are better than raw ones and how to convert an existing code using raw pointers to use smart pointers. For the sake of this post, when I refer to smart pointers, I talk about unique pointers, unique_ptr.
Why is smart pointer better?
Smart pointers have one crucial advantage over raw pointers: they guarantee that their destructors are called during stack unwinding. That means that any memory allocated in constructors will be automatically freed.
Let’s look at sample code, that illustrates the advantage of smart pointers over raw pointers. First, let’s define a simple class that owns some memory, say std::string to store text.
class Test
{
string s;
public:
Test(string sVariable) :
s(sVariable)
{
cout << "Constructor (" << s << ")..." << endl;
};
~Test()
{
cout << "Destructor (" << s << ")..." << endl;
};
};
Now assume that the main function will call myFunction() method to perform some operations. Main will catch any exceptions generated in myFunction() and exit the program.
int main()
{
try
{
myFunction();
}
catch(...)
{
cout << "Exception handled" << endl;
}
cout << "End" << endl;
return 0;
}
Now let’s declare two pointers to Test class in myFunction(). First is rawPointer, which is raw pointer, and then smartPointer which is a smart pointer. Then let’s throw an exception to simulate some unexpected behavior of myFunction. At the end of the function we delete rawPointer. Note, that a smartPointer variable is not deleted as its destructor is guaranteed when the variable goes out of scope.
int myFunction()
{
cout << "raw pointer" << endl;
Test *rawPointer = new Test("raw pointer");
cout << "smart pointer" << endl;
unique_ptr<Test> smartPointer = make_unique<Test>("smart pointer");
cout << "Throw!" << endl;
throw;
cout << "Delete raw pointer" << endl;
delete rawPointer;
return 0;
}
When we run this code, we see the following output:
raw pointer
Constructor (raw pointer)...
smart pointer
Constructor (smart pointer)...
Throw!
Destructor (smart pointer)...
Exception handled
End
Notice, that rawPointer variable is never deleted, causing a memory leak to occur.
How to convert raw pointers to smart pointers?
The above code provides a template how to convert existing code that is using raw pointers to smart pointers. To simplify the instructions, let’s use an example of code using raw pointers to int.
- Convert raw pointer declaration and allocation from
int * rP;
rP = new int;
to
unique_ptr<int> sP = make_unique<int>();
- Remove delete call to release rP memory
That’s it! The code after the conversion is simpler and more robust, as you will never forget to delete the memory, or delete it twice, or the delete will simply be skipped by unexpected code flow (see the example using throw).