C++. Development of a class that implements a “smart” pointer
This topic provides an example of developing a template class that implements a smart pointer.
Contents
- 1. The concept of a “smart” pointer. Features of implementation
- 2. Smart pointer template class example
- 3. Program code analysis
- Related topics
Search other resources:
1. The concept of a “smart” pointer. Features of implementation
The term “smart” pointer means a class that imitates the work of a regular pointer and extends the functionality of this pointer by introducing additional features. Examples of additional features include:
- checks for correct pointer usage limits;
- counting the number of copies of the pointer;
- freeing the memory pointed to by the pointer, etc.
Using a “smart” pointer makes it impossible to try to free the same piece of memory twice. There are times when two or more different pointers point to the same memory location. After freeing this memory in one of the pointers, an attempt to free it through other pointers will generate an exception and the program will crash. If a specially designed “smart” pointer class is used in the program, this situation will be handled correctly.
From the point of view of the implementation in the class, the following internal data (fields) are defined for the “smart” pointer:
- a pointer to an object of the given type. If it is a generic class, then a pointer to an object of the generic type T;
- counter of the number of calls to the object.
To provide minimal smart pointer capabilities in a class, you must implement at least one operator->() operator function that provides access by pointer.
⇑
2. Smart pointer template class example
The code for the two classes is shown below:
- class Int that implements some integer. This class is designed for demonstration purposes. Any other class can be used if desired;
- template class SmartPtr that implements a “smart” pointer.
#include <iostream> using namespace std; // Topic: smart pointers // A class class Int { private: int d; public: // Constructor Int(int _d) : d(_d) { } // Access methods int Get() { return d; } void Set(int _d) { d = _d; } // Method Print() void Print(string msg) { cout << msg.c_str() << d << endl; } }; // Class of smart pointer to generic type T template <typename T> class SmartPtr { private: T* p; // pointer to generic type T int count; // number of copies public: // Constructor SmartPtr(T* _p = nullptr) { // Write 0 - no copies count = 0; p = _p; } // Copy constructor SmartPtr(const SmartPtr& obj) { // A copy is created p = obj.p; // Increase count count++; } // Copy operator SmartPtr operator=(const SmartPtr& obj) { // A copy is created p = obj.p; count++; return *this; } // Destructor - destroys the original object, // copy objects are not destroyed. ~SmartPtr() { // If there is an object and there are no copies, // then we simply destroy this object. if ((p != nullptr) && (count == 0)) { cout << "Delete object" << endl; delete[] p; } else { // otherwise, the copy is simply destroyed cout << "Delete copy" << endl; count--; // decrease copy count } } // Override operator -> access by pointer T* operator->() { return p; } }; void main() { // 1. Create an object of class Int Int* obj1 = new Int(10); obj1->Print("obj1: "); // 2. Initialize a smart pointer with this object SmartPtr<Int> ptr(obj1); ptr->Print("ptr->obj: "); // 3. Create a copy of a smart pointer SmartPtr<Int> ptr2 = ptr; // call the copy constructor ptr2->Print("ptr2->obj: "); // 4. Create another copy of the smart pointer SmartPtr<Int> ptr3; ptr3 = ptr2; // copy operator is called ptr3->Print("ptr3->obj: "); }
After running the program, it will give the following result
obj1: 10 ptr->obj: 10 ptr2->obj: 10 ptr3->obj: 10
⇑
3. Program code analysis
The template class SmartPtr<T> operates on the generic type T. The class declares a constructor that takes a pointer to type T. When the first instance is created, the internal variable count (number of copies) is set to 0. Incrementing this variable is possible in cases where a copy of the pointer is being created. A copy can be created when a copy constructor or copy operator is called. Thus, the number of smart pointer copies created is tracked.
The most important element of a class is the destructor.
~SmartPtr() { // If there is an object and no copies, then we simply destroy this object. if ((p != nullptr) && (count == 0)) { delete[] p; } else { // otherwise, just destroy the copy count--; // decrease copy count } }
As you can see from the destructor code, the memory for the pointer is freed only once, no matter how many copies it has. In fact, the memory for the pointer for which memory was allocated for the first time is released. If a copy is considered, then no memory is deallocated, only the copy counter is decremented. The destructor ensures that the memory is deallocated correctly in case there are copies of the smart pointer.
⇑
Related topics
- General concepts. Pointer types. Managed and unmanaged pointers. Pointers to a function. Examples of the use of pointers
- The concept of class. Class declaration. The object of the class. Classes in the CLR. Data encapsulation in the class
⇑