
- C++ Home
- C++ Overview
- C++ Environment Setup
- C++ Basic Syntax
- C++ Comments
- C++ Hello World
- C++ Omitting Namespace
- C++ Tokens
- C++ Constants/Literals
- C++ Keywords
- C++ Identifiers
- C++ Data Types
- C++ Numeric Data Types
- C++ Character Data Type
- C++ Boolean Data Type
- C++ Variable Types
- C++ Variable Scope
- C++ Multiple Variables
- C++ Basic Input/Output
- C++ Modifier Types
- C++ Storage Classes
- C++ Constexpr Specifier
- C++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- C++ Arithmetic Operators
- C++ Relational Operators
- C++ Logical Operators
- C++ Bitwise Operators
- C++ Assignment Operators
- C++ sizeof Operator
- C++ Conditional Operator
- C++ Comma Operator
- C++ Member Operators
- C++ Casting Operators
- C++ Pointer Operators
- C++ Operators Precedence
- C++ Unary Operators
- C++ Control Statements
- C++ Decision Making
- C++ if Statement
- C++ if else Statement
- C++ Nested if Statements
- C++ switch Statement
- C++ Nested switch Statements
- C++ Loop Types
- C++ while Loop
- C++ for Loop
- C++ do while Loop
- C++ Foreach Loop
- C++ Nested Loops
- C++ break Statement
- C++ continue Statement
- C++ goto Statement
- C++ Strings
- C++ Strings
- C++ Loop Through a String
- C++ String Length
- C++ String Concatenation
- C++ String Comparison
- C++ Functions
- C++ Functions
- C++ Multiple Function Parameters
- C++ Recursive Function
- C++ Return Values
- C++ Function Overloading
- C++ Function Overriding
- C++ Default Arguments
- C++ Arrays
- C++ Arrays
- C++ Multidimensional Arrays
- C++ Pointer to an Array
- C++ Passing Arrays to Functions
- C++ Return Array from Functions
- C++ Structure & Union
- C++ Structures
- C++ Unions
- C++ Class and Objects
- C++ Object Oriented
- C++ Classes & Objects
- C++ Class Member Functions
- C++ Class Access Modifiers
- C++ Static Class Members
- C++ Static Data Members
- C++ Static Member Function
- C++ Inline Functions
- C++ this Pointer
- C++ Friend Functions
- C++ Pointer to Classes
- C++ Constructors
- C++ Constructor & Destructor
- C++ Default Constructors
- C++ Parameterized Constructors
- C++ Copy Constructor
- C++ Constructor Overloading
- C++ Constructor with Default Arguments
- C++ Delegating Constructors
- C++ Constructor Initialization List
- C++ Dynamic Initialization Using Constructors
- C++ Inheritance
- C++ Inheritance
- C++ Multiple Inheritance
- C++ Multilevel Inheritance
- C++ Object-oriented
- C++ Overloading
- C++ Polymorphism
- C++ Abstraction
- C++ Encapsulation
- C++ Interfaces
- C++ Virtual Function
- C++ Pure Virtual Functions & Abstract Classes
- C++ Design Patterns
- C++ Creational Design Patterns
- C++ File Handling
- C++ Files and Streams
- C++ Reading From File
- C++ Advanced
- C++ Exception Handling
- C++ Dynamic Memory
- C++ Namespaces
- C++ Templates
- C++ Preprocessor
- C++ Signal Handling
- C++ Multithreading
- C++ Web Programming
- C++ Socket Programming
- C++ Concurrency
- C++ Advanced Concepts
- C++ Lambda Expression
- C++ unordered_multiset
Smart Pointers in C++
A smart pointer is a class template that wraps around a raw pointer. It is used in memory management to clear the dynamically allocated memory automatically when it is no longer needed. This prevents memory leaks and dangling pointers. They are implemented as templates in the Standard Template Library (STL) (<memory> header).
Memory Leak: In C++, we need to manually clear the dynamically allocated memory. Memory leak occurs when the dynamically allocated memory is not cleared.
Dangling Pointer: It is a pointer that points to the memory address that has been cleared earlier but it still pointing to that deallocated memory address.
Here is an example of memory leak and dangling pointer where the ptr pointer causes a memory leak and the ptr2 pointer becomes a dangling pointer.
#include <iostream> using namespace std; int main(){ int *ptr1 = new int(42); // allocating memory cout << "ptr1 pointer Value: " << *ptr1 << endl; // Here memory leak occurs as we have // not freed the allocated memory int *ptr2 = new int(100); // allocating memory delete ptr2; // clearing the memory // accessing freed memory cout << "ptr2 pointer value: " << *ptr2 << endl; // dangling pointer return 0; }
The output of the above code is as follows −
ptr1 pointer Value: 42 ptr2 pointer value: 1465330567
Types of Smart Pointers
Smart pointers are of 4 types that are mentioned below. You need to use <memory> header to use these smart pointers −
The auto_ptr Pointer
The auto_ptr is a type of smart pointer that automatically manages memory. It is now deprecated since C++11, and removed in C++17 as it uses copy assignments operator to transfer ownership automatically without warning and the original pointer becomes null unexpectedly. This leads to unexpected null pointer access and program can crash.
Here is a simple example of auto_ptr where we are printing the value of ptr1 and ptr2. It will show a warning in the output as it has been deprecated −
#include <iostream> #include <memory> using namespace std; int main() { auto_ptr<int> ptr1(new int(100)); cout << "ptr1 value: " << *ptr1 << endl; auto_ptr<int> ptr2 = ptr1; cout << "ptr2 value: " << *ptr2 << endl; return 0; }
The output of the above code is as follows. As we can see here it gives a warning that auto_pointer has been deprecated −
main.cpp: In function 'int main()': main.cpp:7:5: warning: 'template<class> class std::auto_ptr' is deprecated: use 'std::unique_ptr' instead [-Wdeprecated-declarations] 7 | auto_ptr<int> ptr1(new int(100)); ptr1 value: 100 ptr2 value: 100
The unique_ptr Pointer
The unique_ptr is a smart pointer that owns only one object at a time. It does not copy the pointers from one pointer to other. It transfers its ownership using std::move() function and automatically deletes the memory when the pointer goes out of scope. It solves the problem of auto_ptr and prevent memory leaks. You can use unique_ptr for single ownership.

Below is an example of unique_ptr where the pointer ptr1 transfers its ownership to pointer ptr2 to print the pointer value −
#include <iostream> #include <memory> using namespace std; int main() { unique_ptr<int> ptr1 = make_unique<int>(200); cout << "ptr1 value: " << *ptr1 << endl; unique_ptr<int> ptr2 = move(ptr1); cout << "ptr2 value: " << *ptr2 << endl; return 0; }
The output of the above code is as follows:
ptr1 value: 200 ptr2 value: 200
The shared_ptr Pointer
A shared_ptr is a smart pointer that allows multiple pointers to share ownership of the same object using reference counting, unlike unique_ptr where only one pointer can have the ownership of an object.
It maintains a reference count to keep a track of number of pointers sharing one object. The reference count is decreased when a shared_ptr is destroyed and the object is automatically deleted when count reaches zero. You can use shared_ptr when you need multiple owners of the same object.

Here is an example of shared_ptr where both the pointers share the same object −
#include <iostream> #include <memory> using namespace std; int main() { shared_ptr<int> ptr1 = make_shared<int>(300); cout << "ptr1 value: " << *ptr1 << endl; cout << "Reference count: " << ptr1.use_count() << endl; shared_ptr<int> ptr2 = ptr1; // Both can access the object cout << "\nAfter sharing:" << endl; cout << "ptr1 value: " << *ptr1 << endl; cout << "ptr2 value: " << *ptr2 << endl; cout << "Reference count: " << ptr1.use_count() << endl; return 0; }
The output of the above code is as follows −
ptr1 value: 300 Reference count: 1 After sharing: ptr1 value: 300 ptr2 value: 300 Reference count: 2
The weak_ptr Pointer
A weak_ptr is a non-owning pointer to an object. Unlike shared_ptr, it does not increase the reference count of an object, and it can detect if the object has been destroyed. You can access the object using weak_ptr, but first you must lock the weak_ptr. By locking you get a temporary shared_ptr. It is used to avoid the circular dependency between shared_ptr objects.

Here is an example of accessing an object value 400 using weak_ptr observer −
#include <iostream> #include <memory> using namespace std; int main() { shared_ptr<int> owner = make_shared<int>(400); weak_ptr<int> observer = owner; cout << "shared_ptr reference count: " << owner.use_count() << endl; // Lock to use weak_ptr if (auto locked = observer.lock()) { cout << "Object value: " << *locked << endl; } owner.reset(); cout << endl; return 0; }
The output of the above code is as follows −
shared_ptr reference count: 1 Object value: 400
Pointer vs Smart Pointer
The following table differentiates between a pointer and a smart pointer −
Pointer | Smart Pointer |
---|---|
A pointer stores memory address of another variable or object. | A smart pointer is a class template that wraps around a raw pointer and used for automatic memory management. |
Manually new and delete is called to allocate and deallocate memory. | It uses RAII(Resource Acquisition is Initialization) principles to automatically manage memory for allocation and deallocation. |
It creates chances of memory leak and dangling pointers. | No risk of memory leaks or dangling pointers. |
There is no feature to track the numbers of pointers pointing to an object. | Here, shared_ptr maintains a reference counter to track the number of pointers pointing to the same object. |
It is not destroyed when it goes out of its scope. | It gets automatically destroyed when it goes out of scope. |
Conclusion
Smart pointers in C++ help in automatic memory management that solves the problem of memory leak and dangling pointers. There are four types of smart pointers: auto_ptr, unique_ptr, shared_ptr, and weak_ptr, out of which the auto_ptr has been deprecated.