The purpose of this instruction guide is to teach the user on how to implement the singleton design pattern in their C++ program. In doing so, this instruction set will also explain to the reader why elements of a singleton are the way they are and how the code is processed. Knowing this, will help in the future with debugging your future singletons. What is the singleton design pattern? The singleton design pattern is a design pattern where the coder creates a class that can only be instantiated once, the classes’ public functions can basically be accessed anywhere, provided you have #included the header file in other project related files.
The singleton design pattern is a must know design pattern for any object-oriented programmer, software programmers, and game programmers. The singleton design pattern is also one of the easiest coding design patterns out there. Learning it can help you learn other, more difficult, design patterns in the future. It can also help you to streamline your program’s code in ways you didn’t think was possible.
While the difficulty of the singleton design pattern is easy when compared to other design patterns, this instruction set has a medium difficulty. This means that to do these instructions, we recommend that you know basic and advance syntax requirements of C++. You should also know proper C++ coding etiquette (i.e. Keep class variables private, one class per header file etc.). You should also know how to free up memory and how constructors and destructors work in C++.
This instructional guide will take on average around 10-15 minutes.
-A computer (can be PC or Mac) capable of running Visual Studios (any version)
-A simple program, created in Visual Studios, that you can test your singleton with
Note: The singleton design pattern can be done on any other C++ supporting IDE or coding interface, but for this instruction set, we will be using Visual Studios Enterprise Edition.
Step 1: Create Your Class, With Header File and CPP File
To create these two files and the class all at once, open your project / program in Visual Studios, go over to the solution explorer, right click, and a box should show up near your mouse cursor, find the option “Add”, hover over it, and another box should appear to the right. In this box, you want to find the option “New Item..”, click it and a window, resembling the photo 1.1 image below, should appear. In this window you want to select “C++ Class” and then hit “Add”. This will open another window that resembles the photo 1.2 image. In this window, you type in the name of your class in “Class Name” field and Visual Studios will automatically name the actual file after the class name. For this instruction’s purpose, we are going to name our class “EngineDebugSingleton”, but it can be any letter-based name. You can now hit “OK” and proceed onto step 2.
Note: The solution explorer and where the files are kept on your computer are separate. Moving or creating anything in the solution explorer will not move or organize the files within your OS file explorer. A safe way to organize your files on the file explorer side would be remove, but not delete the specific files from the solution explorer, move the same files in the file explorer to the desired location and then go back to solution explorer, right click, find the option “Add”, then find “Existing Item” and find the files you moved. Make sure you move both the header and cpp file.
Step 2: Set the Constructor to Private
With your newly created CPP file and header file, if it didn’t open automatically when you created it, go to the solution explorer and click and open the “EngineDebugSingleton.h”. You will then be greeted with a “EngineDebugSingleton()”, the class default constructor and “~EngineDebugSingleton()” the class destructor. For this step, we will want to set the constructor to the private, this means that this function is only available to the class and nothing else. With this, you won’t be able to make a variable or allocate the class to memory outside the class, only in the classes’ header file and the classes’ other functions. Having the constructor private is key to the design pattern and how singletons operate. We will discover in future steps how a singleton is instantiated and accessed.
The class should now look like this after moving the constructor to private (Look at associated photo)
Step 3: Set the Destructor to Private
Like we did with the constructor in
step 2, for this step, we will now set the destructor to private. Like with the constructor, nothing, except the class itself, will be able to delete any variables of the class from memory.
The class should now look like this after completing this step. (See Associated photo)
Step 4: Creating a Static Pointer Variable in the Singleton
In this step, we will create a
static pointer variable of type “EngineDebugSingleton*”. This will be the variable that will be used allocate our singleton to memory and will point to it for the entire time our singleton is allocated to memory.
This is what our header file should look like after creating this variable
Step 5: Creating an Instance Function
We now want to make an instance
function. The function will need to be a static function and will want to return a reference to our class (“EngineDebugSingleton&”). We called our function Instance(). In the function itself, we will want to first test if ptrInstance == nullptr (can be shortened to !ptrInstance), if it is nullptr, this means that the singleton has not been allocated and in the scope of the if statement, we will want to allocate by doing ptrInstance = new EngineDebugSingleton(). This is where you actually allocate the singleton to memory. After exiting the scope of the if statement, we will then return what ptrInstance is pointing to, which is denoted by the syntax “*ptrInstance”. We will be using this function heavily when making our static public functions, so we can check to see if the singleton has been created and allocated to memory. In essence, this function makes it so you can have only one allocation of the class and no more.
This is what our class should look like now after creating the Instance() function. As you can see, all of what we’ve done has stayed in the private section of the class, this is going to change a little in the next few steps.
Step 6: Creating Static Public Functions
After you’ve made the function from
step 5, you can begin to make static public functions. Every public function should have a private function to go along with it, the name of this function cannot be the same. Why make the function Static? We’re making the public functions static so they can be accessed without an actual object. So instead of doing something like “EngineDebugSingleObj->SomeFunction()”, we do “EngineDebugSingleton:: Some Function()”. This makes it possible for a singleton to be accessed basically anywhere in code, provided you’ve #included the header file in the specific project file you’re working with. With this, you can also create the singleton through any of its’ public functions.
For our purposes in this step we created two public static void functions, “add()” and “subtract()”. In the private section, we two more functions, “PrivAdd()” and “PrivSubtract()”. We also added an int variable called “NumberOfThings”. The definition for these functions will go into our classes’ CPP file. To easily make the function get into the CPP file, you highlight, with your cursor, the function, which should have a green line under it, and hit “Left ALT + ENTER”, it will give you the option create the definition in the classes’ associated CPP file. See Photo 6.1 to see what the header file should look like and after you’ve created the all the function definitions, your CPP should look like Photo 6.2 except that your function definitions will have no code in them.
You will now want to add the same code as in Photo 6.2 into your function definitions. As stated earlier, our public functions will be making use of the Instance() function, which will return what ptrInstance is pointing to. This allows us to access the private functions of our class. With any singleton’s public function, you should only be calling that Instance function. The only exception to this is our Terminate function.
Note: The exact public and private functions shown in this step aren’t necessary, you can have different function names and operations in the private function, but for any type of public function, you should have a private function to go along with it and the public function should always use, in our case, the Instance() function.
Step 7: Creating the Terminate Function
Since we can only deallocate our singleton from memory in our class, we must create a static public function. This function will call delete on ptrInstance, which calls the class destructor and then we will want to set ptrInstance back to nullptr so it can be allocated again if your program doesn’t end. You will also want to terminate your Singletons to clean up any allocated memory that you allocated in any Singleton’s private variables.
Step 8: Setting PtrInstance to Nullptr
To complete your singleton, you want to head over to EngineDebugSingleton.CPP file and at the top of the CPP file, in our instance, type “EngineDebugSingleton* EngineDebugSingleton::ptrInstance = nullptr.”
Doing this will initially set ptrInstance to nullptr, so when you first go through the instance function for the first time, our class will be allowed to be allocated to memory. Without it, you will most likely get an error because you will be trying to access memory that has nothing allocated to it.
Step 9: Test and Conclusion
We will now want to test that our singleton to make sure it works, this will involve us calling the public functions like as described in step 6 and we recommend that you set up breakpoints to step through your code and see that the singleton is working as it should be. Our starting point will be in our project’s main.cpp and our main.cpp now looks like the image below.
Congratulations! You’ve just
completed your first implementation of the Singleton Design Pattern. With this design pattern, you can now streamline your code in a variety of ways. For example, you now can make manager systems that operate across your program’s run time, which can be accessed through static functions anywhere where you’ve included the class.
Your final header file should look like the photo 7.1. Your singleton’s associated CPP file should look like Photo 6.2 with the addition of, at the top of the file, of the code shown in step 8. This instruction provided you with a simple structure of the Singleton Design Pattern.
Getting memory related errors?
Make sure you refer to step 7 and step 8 to make sure you’re setting ptrInstance to nullptr.
Infinite loop occurring?
Make sure for the public functions, in their definitions, you are calling the private function, not the same public function.
Objects allocated within the singleton causing memory leaks?
Make sure you call your singleton’s terminate function when appropriate within your program code, and in the destructor of your singleton, make sure you de-allocate any objects that were allocated to memory within the scope of the singleton code.