Smart pointers - Are they really that smart?

Published:
Updated:
Smart pointers - Are they really that smart?

You might have heard something called smart pointers on your lectures, or that many game companies use them. The reason why just you, should use them might not be clear. Even if you would want to use them you may not know how you do that. The reason why you may not know that, is because the use of templates. Without templates, these smart pointers would actually be more accurate called "dumb pointers." We will cover "dumb pointers" later in our goal to achieve smart pointers.

What are smart pointers, and what are they good for?

Smart pointers is basicly your typical object. However, this object is built to be a container of sorts, a container that stores another object of chosen type. This container can then later call upon it's content and all it's member methods and attributes. That gives us the very specific advantage of calling upon the content object deconstructor, meaning removing it from memory automatically.

The reason why this are good, is pretty straight forward. To decrease the number of bugs you probably will run into, if you would not to be using it.

When you create a program, you do not want memory leakage or memory that takes room without reason. Ideally, you want to load your object into memory, and delete it as soon as it is not going to be used again.

The most common error, that will happen in your program, will be that you allocate memory, and never release it. When you create a object in the memory (using pointers) you have to delete it. This is sometimes something many programmers forget, not because they are lazy or dumb, but because they say they will get to it later.

They continue to say that as the code grows, and finally ends up being over 10 000 rows of code. Having bugs appearing with that much code, is to put it mildly, not fun.

Here comes the smart pointers to rescue. They will automatically when your program shuts down, remove any content you have stored inside it, hence eliminating all sorts of memory leakage.

How do i get started creating my own class for smart pointers?

This will be divided into two steps, firstly for those of you who do not understand or have used templates in c++ before. This step will be called "dumb pointers." The second step, will be called smart pointers. If you feel that you have good enough knowledge about how to use and create templates, you can jump straight to that step.

Step 1 - Making dumb pointers

Imagine the scenario where we have the following class:

//Player.h - Header file
                      #pragma once
                      #include <iostream>
                      
                      class Player
                      {
                      public:
                      	Player(void);
                      	void SayHi();
                      	~Player(void);
                      };

Open in new window


//Player.cpp - Source file
#include "Player.h"
                      
                      
                      Player::Player(void)
                      {
                      }
                      
                      void Player::SayHi()
                      {
                      	std::cout << "Derp derp" << std::endl;
                      }
                      
                      
                      Player::~Player(void)
                      {
                      	std::cout << "Master Removed me" << std::endl;
                      }

Open in new window


and then we have the main.cpp with the following code:

#include <iostream>
                      #include "auto_ptr.h"
                      #include "Player.h"
                      
                      using namespace std;
                      
                      int main()
                      {
                      	Player *dumbpointer = new Player();
                      	dumbpointer->SayHi();
                              //deallocate memory, and set the pointer to null, thanks Sara
                              delete dumbpointer;
                      	dumbpointer = NULL;
                      
                      
                      	system("pause");
                      	return 0;
                      }

Open in new window


What we do here, is to allocate memory dynamicly, by using directive "new". The memory address to this allocation will be stored in our pointer, named "dumbpointer" of our class Player. Now dumbpointer simply points on the dynamicly allocated object, and we can use the operator -> to gain access to it from our code.

When we write dumbpointer->SayHi(); the code will look what the dumbpointer points to, and go there to find the function we called. Later we have to call delete dumbpointer, to make sure no memoery leak occurs. That's all it does. It only points. What if pointers could do more? Like noticing when the program exits, and no longer point.

Imagine someone in real life pointing at a house that no longer exists. That would be kind of weird huh? This is when smart pointers comes to the rescue!

Step 2 - Making smart pointers

When making smart pointers, you have to utilize templates. The reason why, is because you do not know what type of object you want your smart pointer to contain. Up until your first time using templates you always had to declare what type of object you want to use or create. Like a string, int or bool. Template holds whatever type we want, without us having to declare overloads or several attributes that holds that type. You can think that templates are holding types, that are chosen when you compile your code.

How can I make this smart pointer with template class? Here we only need one thing, a header file called auto_ptr.h

//Tell the compiler that we are making a template class, that can support all kind of types.
                      //The type we later choose, will be stored in the identifer T.
                      template <class T> 
                      class auto_ptr
                      {
                      public:
                      	//explicit = Disable the use of auto_ptr<type> obj = something;
                      	//Constructor
                      	explicit auto_ptr(T* pointer) : ptr(pointer){};
                      
                      	//Deconstructor, will automaticly remove the object from memory when we reach eop (end of program)
                      	~auto_ptr()
                      	{
                      		delete ptr;
                      	}
                      	//Link so that when a pointer is used with our auto_ptr, it will be linked to the contained object inside our auto_ptr instead.
                      	T& operator*()
                      	{
                      		return *ptr;
                      	}
                      	//When we use the operator -> we want it to return the contained object inside auto_ptr too.
                      	T* operator->()
                      	{
                      		return ptr;
                      	}
                      private:
                      	//Our member attribute, which stores the object we want contained in our auto_ptr
                      	T* ptr;
                      };

Open in new window


When we later implement this class in our main.cpp we do like this:

#include <iostream>
                      #include "auto_ptr.h"
                      #include "Player.h"
                      
                      using namespace std;
                      
                      int main()
                      {
                      	auto_ptr<Player> smartplayer(new Player);
                      	smartplayer->SayHi();
                      
                      	system("pause");
                      	return 0;
                      }

Open in new window


What we do here, is to create our smart pointer. By writing <Player>, we tell our template class that T should store the type Player, which is the class we created. This means we can now look at our auto_ptr class, and imagine that instead of writing T in front of our operator overloads, we write Player. This should make everything much more clearer to you. Yes the result from our function will now give back a response that is of the type Player.

Except for how you create this smart pointer, its pretty similar to how you created the dumb pointer. When you call the identifier later, it looks the same as if it would be the dumb pointer. However, as soon as the program closes, the auto_ptr deconstructor will be called and directly remove our Player allocation from memory. This is something the dumb pointer will not, unless we specify it to do so with the directive delete.

Step 3 - Smart pointers and praxis

The above text should make you see the advantages of using smart pointers. However this class is not something you should use in your application. There are already several solutions of smart_pointers out there that will support many many more different solutions and work much better than the above smart pointer class does.

The new std has a set of these smart pointers. To name a few: std::unique_ptr, std::shared_ptr and std::weak_ptr.

Although, a open source library that exists today called boost, may be more to your liking.
The boost library has several advantages, and is a library that is used in for instance CryEngine 1,2 and 3.

You can find the boost library here: http://www.boost.org/
0
2,929 Views

Comments (3)

CERTIFIED EXPERT
Top Expert 2016

Commented:
it is a nice article.

but did i miss the point where you explained why the following statements were in wrong order?

dumbpointer = NULL;
delete dumbpointer;

Open in new window


Sara

Author

Commented:
Hi Sara, this is actually a typo from my end. Naturally it should deallocate the memory, and then set the pointer to null. Thanks for spotting it for me :)
evilrixEngineering Manager
CERTIFIED EXPERT

Commented:
I covered the full implementation of reference counted smart pointers here:
https://www.experts-exchange.com/articles/1959/C-Smart-pointers.html

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.