Smart pointers are a feature introduced in C++11 to manage dynamic memory allocation more efficiently and safely than raw pointers. They are called “smart” because they not only act like pointers but also manage the memory they point to automatically. Smart pointers ensure proper memory deallocation, preventing memory leaks and dangling pointers, which are common pitfalls with raw pointers.
There are three types of smart pointers provided by the C++ Standard Library: std::unique_ptr
, std::shared_ptr
, and std::weak_ptr
.
- std::unique_ptr:
std::unique_ptr
is a smart pointer that owns the memory it points to.- It ensures that there is only one
std::unique_ptr
instance pointing to the allocated memory. - When the
std::unique_ptr
goes out of scope or is explicitly deleted, it automatically deallocates the memory it owns. - Ownership of the memory cannot be shared or transferred.
- std::shared_ptr:
std::shared_ptr
is a smart pointer that allows multiple pointers to share ownership of the same allocated memory.- It keeps track of the number of
std::shared_ptr
instances pointing to the memory. - The memory is deallocated only when the last
std::shared_ptr
pointing to it is destroyed. - It provides a form of automatic garbage collection, as memory is automatically released when it is no longer in use.
- std::weak_ptr:
std::weak_ptr
is a smart pointer that does not participate in ownership of the allocated memory.- It is used in conjunction with
std::shared_ptr
to break cyclic dependencies and prevent memory leaks. - It provides a non-owning reference to an object managed by
std::shared_ptr
. - It can be used to check if the memory it points to is still valid, but it does not prevent the memory from being deallocated.
Example Program:
#include <iostream>
#include <memory>
int main() {
// Using unique_ptr
std::unique_ptr<int> uniquePtr(new int(42));
std::cout << "Value stored in uniquePtr: " << *uniquePtr << std::endl;
// Using shared_ptr
std::shared_ptr<int> sharedPtr1 = std::make_shared<int>(10);
std::shared_ptr<int> sharedPtr2 = sharedPtr1;
std::cout << "Value stored in sharedPtr1: " << *sharedPtr1 << std::endl;
std::cout << "Value stored in sharedPtr2: " << *sharedPtr2 << std::endl;
// Using weak_ptr
std::shared_ptr<int> sharedPtr3 = std::make_shared<int>(20);
std::weak_ptr<int> weakPtr(sharedPtr3);
std::cout << "Value stored in weakPtr: ";
if (auto ptr = weakPtr.lock()) {
std::cout << *ptr << std::endl;
} else {
std::cout << "Memory is no longer valid." << std::endl;
}
return 0;
}
Line by Line Explanation:
- Include necessary header files for the program.
- Main function begins.
- Create a
std::unique_ptr
nameduniquePtr
pointing to a dynamically allocated integer with value 42. - Output the value stored in
uniquePtr
. - Create two
std::shared_ptr
instances,sharedPtr1
andsharedPtr2
, both pointing to a dynamically allocated integer with value 10. SincesharedPtr1
andsharedPtr2
share ownership, they both point to the same memory location. - Output the values stored in
sharedPtr1
andsharedPtr2
. - Create a
std::shared_ptr
namedsharedPtr3
pointing to a dynamically allocated integer with value 20. Create astd::weak_ptr
namedweakPtr
pointing to the same memory location assharedPtr3
. - Output the value stored in
weakPtr
. If the memory is still valid (i.e.,weakPtr
can be converted to astd::shared_ptr
), output the value. Otherwise, indicate that the memory is no longer valid. - End of the
main
function.
Smart Pointer – Basic Usage with std::unique_ptr
Introduction: This program demonstrates the basic usage of std::unique_ptr
smart pointer.
#include <iostream>
#include <memory>
int main() {
// Create a unique pointer to an integer
std::unique_ptr<int> ptr(new int(5));
// Access the value using the dereference operator
std::cout << "Value of ptr: " << *ptr << std::endl;
// Release the memory explicitly
ptr.reset();
return 0;
}
Explanation:
#include <memory>
: Includes the necessary header for smart pointers.std::unique_ptr<int> ptr(new int(5));
: Declares a unique pointerptr
to an integer dynamically allocated with value5
.std::cout << "Value of ptr: " << *ptr << std::endl;
: Accesses the value pointed byptr
using the dereference operator.ptr.reset();
: Releases the memory explicitly by calling thereset
method ofstd::unique_ptr
.
This program demonstrates the basic usage of std::unique_ptr
smart pointer.
Smart Pointer – Shared Ownership with std::shared_ptr
Introduction: This program demonstrates the shared ownership semantics of std::shared_ptr
smart pointer.
#include <iostream>
#include <memory>
void displayCount(std::shared_ptr<int> ptr) {
std::cout << "Reference count: " << ptr.use_count() << std::endl;
}
int main() {
// Create a shared pointer to an integer
std::shared_ptr<int> ptr1(new int(5));
// Display reference count
displayCount(ptr1);
// Create another shared pointer to the same integer
std::shared_ptr<int> ptr2 = ptr1;
// Display reference count
displayCount(ptr1);
displayCount(ptr2);
// Release memory
ptr1.reset();
// Display reference count
displayCount(ptr2);
return 0;
}
Explanation:
void displayCount(std::shared_ptr<int> ptr)
: A function to display the reference count of a shared pointer.std::shared_ptr<int> ptr1(new int(5));
: Declares a shared pointerptr1
to an integer dynamically allocated with value5
.displayCount(ptr1);
: Displays the reference count ofptr1
.std::shared_ptr<int> ptr2 = ptr1;
: Declares another shared pointerptr2
and shares ownership withptr1
.displayCount(ptr1);
,displayCount(ptr2);
: Displays the reference count ofptr1
andptr2
.ptr1.reset();
: Releases the memory held byptr1
.displayCount(ptr2);
: Displays the reference count ofptr2
after releasing the memory byptr1
.
This program demonstrates the shared ownership semantics of std::shared_ptr
smart pointer.
Smart Pointer – Avoiding Memory Leaks with std::unique_ptr
Introduction: This program demonstrates how std::unique_ptr
helps in avoiding memory leaks.
#include <iostream>
#include <memory>
void createResource() {
// Create a unique pointer to dynamically allocated memory
std::unique_ptr<int> ptr(new int(10));
// Use the resource
std::cout << "Value of ptr: " << *ptr << std::endl;
// Memory is automatically released when ptr goes out of scope
}
int main() {
createResource();
// No need to release memory explicitly
return 0;
}
Explanation:
void createResource()
: A function to demonstrate dynamic memory allocation and automatic memory release.std::unique_ptr<int> ptr(new int(10));
: Declares a unique pointerptr
to an integer dynamically allocated with value10
.std::cout << "Value of ptr: " << *ptr << std::endl;
: Accesses the value pointed byptr
.- Memory allocated by
ptr
is automatically released whenptr
goes out of scope, avoiding memory leaks.
This program demonstrates how std::unique_ptr
helps in avoiding memory leaks by automatically releasing dynamically allocated memory when the pointer goes out of scope.
Introduction: Weak Pointer
This program demonstrates the usage of std::weak_ptr
smart pointer in C++. Unlike std::shared_ptr
, std::weak_ptr
does not participate in reference counting and does not keep the managed object alive. It is typically used to break circular references between std::shared_ptr
s.
#include <iostream>
#include <memory>
class Node {
public:
int data;
std::weak_ptr<Node> next;
Node(int value) : data(value) {
std::cout << "Node with data " << data << " created" << std::endl;
}
~Node() {
std::cout << "Node with data " << data << " destroyed" << std::endl;
}
};
int main() {
// Creating shared pointers to nodes
std::shared_ptr<Node> node1 = std::make_shared<Node>(1);
std::shared_ptr<Node> node2 = std::make_shared<Node>(2);
// Creating a weak pointer to node2
node1->next = node2;
// Checking if the weak pointer is expired
if (auto sharedPtr = node1->next.lock()) {
std::cout << "Data of next node: " << sharedPtr->data << std::endl;
} else {
std::cout << "Next node is no longer available" << std::endl;
}
// Resetting node2
node2.reset();
// Checking if the weak pointer is expired after resetting node2
if (auto sharedPtr = node1->next.lock()) {
std::cout << "Data of next node: " << sharedPtr->data << std::endl;
} else {
std::cout << "Next node is no longer available" << std::endl;
}
return 0;
}
Explanation:
class Node
: Defines a class representing a node in a linked list. It has an integer data and a weak pointernext
to the next node.Node(int value)
: Constructor initializes the node with the given value.~Node()
: Destructor prints a message when the node is destroyed.main()
: The main function demonstrates the usage ofstd::weak_ptr
.std::shared_ptr<Node> node1 = std::make_shared<Node>(1);
: Creates a shared pointer to a node with value1
.std::shared_ptr<Node> node2 = std::make_shared<Node>(2);
: Creates a shared pointer to a node with value2
.node1->next = node2;
: Assignsnode2
to thenext
pointer ofnode1
.node1->next.lock()
: Checks if the weak pointernext
is still valid. If it is, it returns a shared pointer, otherwise, it returns a null pointer.node2.reset()
: Resetsnode2
, effectively destroying it.- The program demonstrates how
std::weak_ptr
can be used to break circular references and how to check if the weak pointer is still valid.
This program illustrates the usage of std::weak_ptr
smart pointer in C++.
These examples provide a detailed understanding of smart pointers in C++.