How to Implement User Defined Shared Pointers in C++?
Last Updated :
11 Jul, 2025
shared_ptr is one of the smart pointer introduced as a wrapper to the old raw pointers in C++ to help in avoiding the risks and errors of raw pointers. In this article, we will learn how to implement our own user defined shared pointer in C++.
What is shared_ptr in C++?
A std::shared_ptr is a container for raw pointers. It is a reference counting ownership model i.e. it maintains the reference count of its contained pointer in cooperation with all copies of the std::shared_ptr. So, the counter is incremented each time a new pointer points to the resource and decremented when destructor of the object is called.
Reference Counting
It is a technique of storing the number of references, pointers or handles to a resource such as an object, block of memory, disk space or other resources.
An object referenced by the contained raw pointer will not be destroyed until reference count is greater than zero i.e. until all copies of std::shared_ptr have been deleted.
Points to Consider when Counting Number of References
- When a new shared pointer is constructed from the raw pointer, initialize the reference counter as 1.
- When a new shared pointer is assigned with some other shared pointer, the reference counter for that reference is increased by one.
- When an old shared pointer is assigned with some other shared pointer (both pointing to different memory location), the count of the reference pointed by the first shared pointer is decreased while the count of the second shared pointer is increased.
When to Use Shared Pointer?
We should use shared_ptr when we want to assign one raw pointer to multiple owners. For more information and details about shared and other smart pointers, please read here.
C++ Program for User Defined Implementation of Shared Pointer
CPP
#include <iostream>
using namespace std;
// Class representing a reference counter class
class Counter
{
public:
// Constructor
Counter() : m_counter(0){};
Counter(const Counter&) = delete;
Counter& operator=(const Counter&) = delete;
// Destructor
~Counter() {}
// count reset
void reset()
{
m_counter = 0;
}
// getter
unsigned int get()
{
return m_counter;
}
// Overload post/pre increment
void operator++()
{
m_counter++;
}
void operator++(int)
{
m_counter++;
}
// Overload post/pre decrement
void operator--()
{
m_counter--;
}
void operator--(int)
{
m_counter--;
}
// Overloading << operator
friend ostream& operator<<(ostream& os,
const Counter& counter)
{
os << "Counter Value : " << counter.m_counter
<< endl;
return os;
}
private:
unsigned int m_counter{};
};
// Class template representing a shared pointer
template <typename T>
class Shared_ptr
{
public:
// Constructor
Shared_ptr(T* ptr = nullptr)
{
m_ptr = ptr;
m_counter = new Counter();
(*m_counter)++;
}
// Copy constructor
Shared_ptr(Shared_ptr<T>& sp)
{
// initializing shared pointer from other Shared_ptr object
m_ptr = sp.m_ptr;
// initializing reference counter from other shared pointer
m_counter = sp.m_counter;
(*m_counter)++;
}
// reference count getter
unsigned int use_count()
{
return m_counter->get();
}
// shared pointer getter
T* get()
{
return m_ptr;
}
// Overload * operator
T& operator*()
{
return *m_ptr;
}
// Overload -> operator
T* operator->()
{
return m_ptr;
}
// overloading the = operator
void operator= (Shared_ptr sp) {
// if assigned pointer points to the some other location
if (m_ptr != sp.m_ptr) {
// if shared pointer already points to some location
if(m_ptr && m_counter) {
// decrease the reference counter for the previously pointed location
(*m_counter)--;
// if reference count reaches 0, deallocate memory
if((m_counter->get()) == 0) {
delete m_counter;
delete m_ptr;
}
}
// reference new memory location
m_ptr = sp.m_ptr;
// increase new memory location reference counter.
if(m_ptr) {
m_counter = sp.m_counter;
(*m_counter)++;
}
}
}
// Destructor
~Shared_ptr()
{
(*m_counter)--;
if (m_counter->get() == 0)
{
delete m_counter;
delete m_ptr;
}
}
friend ostream& operator<<(ostream& os,
Shared_ptr<T>& sp)
{
os << "Address pointed : " << sp.get() << endl;
os << *(sp.m_counter) << endl;
return os;
}
private:
// Reference counter
Counter* m_counter;
// Shared pointer
T* m_ptr;
};
int main()
{
// ptr1 pointing to an integer.
Shared_ptr<int> ptr1(new int(151));
cout << "--- Shared pointers ptr1 ---\n";
*ptr1 = 100;
cout << " ptr1's value now: " << *ptr1 << endl;
cout << ptr1;
{
// ptr2 pointing to same integer
// which ptr1 is pointing to
// Shared pointer reference counter
// should have increased now to 2.
Shared_ptr<int> ptr2 = ptr1;
cout << "--- Shared pointers ptr1, ptr2 ---\n";
cout << ptr1;
cout << ptr2;
{
// ptr3 pointing to same integer
// which ptr1 and ptr2 are pointing to.
// Shared pointer reference counter
// should have increased now to 3.
Shared_ptr<int> ptr3(ptr2);
cout << "--- Shared pointers ptr1, ptr2, ptr3 "
"---\n";
cout << ptr1;
cout << ptr2;
cout << ptr3;
}
Shared_ptr<int> temp(new int(11));
ptr2 = temp;
// ptr3 is out of scope.
// It would have been destructed.
// So shared pointer reference counter
// should have decreased now to 2.
cout << "--- Shared pointers ptr1, ptr2 ---\n";
cout << ptr1;
cout << ptr2;
}
// ptr2 is out of scope.
// It would have been destructed.
// So shared pointer reference counter
// should have decreased now to 1.
cout << "--- Shared pointers ptr1 ---\n";
cout << ptr1;
return 0;
}
Output: --- Shared pointers ptr1 ---
Address pointed : 0x1cbde70
Counter Value : 1
--- Shared pointers ptr1, ptr2 ---
Address pointed : 0x1cbde70
Counter Value : 2
Address pointed : 0x1cbde70
Counter Value : 2
--- Shared pointers ptr1, ptr2, ptr3 ---
Address pointed : 0x1cbde70
Counter Value : 3
Address pointed : 0x1cbde70
Counter Value : 3
Address pointed : 0x1cbde70
Counter Value : 3
--- Shared pointers ptr1, ptr2 ---
Address pointed : 0x1cbde70
Counter Value : 2
Address pointed : 0x1cbde70
Counter Value : 2
--- Shared pointers ptr1 ---
Address pointed : 0x1cbde70
Counter Value : 1
Similar Reads
How to Create a shared_ptr in C++? A std::shared_pointer is a smart pointer introduced in C++11 that manages the lifetime of a dynamically allocated object through reference counting. In this article, we will learn how to create a shared_pointer. shared_ptr in C++A std::shared_pointer can be created by using the std::make_shared meth
2 min read
How to Create a Smart Pointer in C++? A smart pointer in C++ simulates a pointer while also providing automatic garbage collection as it deallocates or frees associated memory when it goes out of scope, which helps prevent memory leaks and dangling pointers. In this article, we will learn how to create a smart pointer in C++. Creating a
4 min read
How to Implement Custom Hash Functions for User-Defined Types in std::unordered_map? In C++ std::unordered_map is a data structure that implements a hash table and allows fast access to each element based on its key. However, when we want to use user-defined types as keys, we need to provide a custom hash function. In this article, we will learn how to implement a custom hash functi
3 min read
How to use const with Pointers in C++? In C++, the const keyword is used as a type qualifier for defining read-only (immutable) objects that cannot be modified anywhere in their lifetime. It can be used in several ways with pointers, each serving a different purpose. In this article, we will learn how to use const qualifier with pointers
3 min read
How to Implement Move Assignment Operator in C++? In C+, the move assignment operator is used to transfer the ownership of the resources from one object to another when the object is assigned some rvalue references or using std::move. It allows efficient memory manipulation by avoiding unnecessary copies of the objects. In this article, we will lea
3 min read
How to Create Vectors of Unique Pointers in C++? In C++, the vector is defined as a dynamic array that can grow or shrink in size. Vectors of unique pointers are commonly used to manage the collections of dynamically allocated objects as they combine the dynamic resizing capability of vectors with the automatic memory management provided by unique
2 min read