How to Avoid Memory Leaks When Using a Vector of Pointers to Dynamically Allocated Objects in C++?
Last Updated :
07 Aug, 2024
In C++, managing memory properly is very important to avoid memory leaks, especially when working with dynamically allocated objects. When using a std::vector of pointers to dynamically allocated objects, we need to ensure that all allocated memory is properly deallocated. In this article, we will learn different methods to avoid memory leaks in such scenarios.
Avoiding Memory Leaks in C++
There are several ways to manage memory effectively when using a std::vector of pointers to dynamically allocated objects:
- Using smart pointers
- Manually deleting objects
- Using custom deleters
1. Using Smart Pointers
Smart pointers, such as std::unique_ptr and std::shared_ptr, automatically manage the lifetime of objects, ensuring that they are properly deallocated when no longer needed.
Example:
C++
// C++ program demonstrating the use of unique_ptr with a vector of objects
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// Define the MyClass class
class MyClass
{
public:
// Constructor that takes an integer value
MyClass(int value) : value(value)
{
// Print message when constructor is called
cout << "Constructor called for " << value << endl;
}
// Destructor
~MyClass()
{
// Print message when destructor is called
cout << "Destructor called for " << value << endl;
}
// Getter for the value
int getValue() const
{
return value;
}
private:
// Private member variable to store the value
int value;
};
int main()
{
// Vector of unique pointers to MyClass objects
vector<unique_ptr<MyClass>> vec;
// Create 5 MyClass objects and add them to the vector
for (int i = 0; i < 5; ++i)
{
vec.push_back(make_unique<MyClass>(i));
}
// Iterate over the vector and print the value of each MyClass object
for (const auto &ptr : vec)
{
cout << "Value: " << ptr->getValue() << endl;
}
return 0;
}
OutputConstructor called for 0
Constructor called for 1
Constructor called for 2
Constructor called for 3
Constructor called for 4
Value: 0
Value: 1
Value: 2
Value: 3
Value: 4
Destructor called for 0
Destructor called for 1
Destructor called for 2
Destructor called for 3
Destructor called for 4
2. Manually Deleting Objects
If we are not using smart pointers, we need to manually delete the objects to avoid memory leaks. Ensure that each dynamically allocated object is deleted when no longer needed.
Example:
C++
// C++ program to demonstrate the use of raw pointers with vector
#include <iostream>
#include <vector>
using namespace std;
// Class definition
class MyClass
{
public:
// Constructor that initializes the value and outputs a message
MyClass(int value) : value(value)
{
cout << "Constructor called for " << value << endl;
}
// Destructor that outputs a message
~MyClass()
{
cout << "Destructor called for " << value << endl;
}
// Getter function to access the value
int getValue() const
{
return value;
}
private:
// Data member to store the value
int value;
};
int main()
{
// Vector to store raw pointers to MyClass objects
vector<MyClass *> vec;
// Create and add MyClass objects to the vector
for (int i = 0; i < 5; ++i)
{
// Create a new MyClass object and add it to the vector
vec.push_back(new MyClass(i));
}
// Output the value of each MyClass object in the vector
for (const auto &ptr : vec)
{
// Access and print the value using the pointer
cout << "Value: " << ptr->getValue() << endl;
}
// Manually delete the MyClass objects to avoid memory leaks
for (auto ptr : vec)
{
// Free the memory allocated for each MyClass object
delete ptr;
}
return 0;
}
OutputConstructor called for 0
Constructor called for 1
Constructor called for 2
Constructor called for 3
Constructor called for 4
Value: 0
Value: 1
Value: 2
Value: 3
Value: 4
Destructor called for 0
Destructor called for 1
Destructor called for 2
Destructor called for 3
Destructor called for 4
Using Custom Deleters
In some cases, we may want to use custom deleters to manage the deletion of objects in a more controlled manner. Custom deleters can be used with smart pointers like std::unique_ptr.
Example:
C++
// C++ program to demonstrate the use of custom deleters with unique_ptr and vector
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// Class definition
class MyClass
{
public:
// Constructor that initializes the value and outputs a message
MyClass(int value) : value(value)
{
cout << "Constructor called for " << value << endl;
}
// Destructor that outputs a message
~MyClass()
{
cout << "Destructor called for " << value << endl;
}
// Getter function to access the value
int getValue() const
{
return value;
}
private:
int value; // Data member to store the value
};
// Custom deleter function that outputs a message and deletes the object
void customDeleter(MyClass *ptr)
{
cout << "Custom deleter called for " << ptr->getValue() << endl;
// Free the memory allocated for the MyClass object
delete ptr;
}
int main()
{
// Vector to store unique_ptr with custom deleter
vector<unique_ptr<MyClass, void (*)(MyClass *)>> vec;
// Create and add MyClass objects to the vector using unique_ptr with a custom deleter
for (int i = 0; i < 5; ++i)
{
vec.push_back(unique_ptr<MyClass, void (*)(MyClass *)>(new MyClass(i), customDeleter));
}
// Output the value of each MyClass object in the vector
for (const auto &ptr : vec)
{
cout << "Value: " << ptr->getValue() << endl; // Access and print the value using the unique_ptr
}
// No need to manually delete objects as unique_ptr with custom deleter will handle it
return 0;
}
OutputConstructor called for 0
Constructor called for 1
Constructor called for 2
Constructor called for 3
Constructor called for 4
Value: 0
Value: 1
Value: 2
Value: 3
Value: 4
Custom deleter called for 0
Destructor called for 0
Custom deleter called for 1
Destructor called for 1
Custom deleter called for 2
Destructor called for 2
Custom deleter called for 3
Destructor called for 3
Custom deleter called for 4
Destructor called for 4
Need of Proper Memory Management
- Avoiding memory leaks ensures that your program runs efficiently and does not consume more memory than necessary.
- Proper memory management prevents crashes and undefined behavior caused by dangling pointers or memory corruption.
- Clear and concise memory management practices make your code easier to understand, maintain, and extend.
Similar Reads
How to create an Array of Objects in the Stack memory? What is an Array of Objects? An array of objects is a data structure that stores a collection of objects of the same type. The objects in the array are stored in contiguous memory locations, and the array provides indexed access to the objects. This means that you can access an individual object in
6 min read
If memory allocation using new is failed in C++ then how it should be handled? In this article, if memory allocation using new is failed in C++ then how it should be handled? When an object of a class is created dynamically using new operator, the object occupies memory in the heap. Below are the major thing that must be keep in mind: What if sufficient memory is not available
3 min read
How to dynamically allocate a 3D array in C++ Prerequisite: Array BasicsIn C/C++, multidimensional arrays in simple words as an array of arrays. Data in multidimensional arrays are stored in tabular form (in row major order). Below is the general form of declaring N-dimensional arrays: Syntax of a Multidimensional Array: data_type array_name[si
4 min read
Using Non-Member Friend Functions With Vector in C++ STL In C++, Non-member buddy functions may access a class's private members while not being members. The class definition declares them friend. Vector containers, dynamic arrays in C++ Standard Library (STL), may dynamically resize as members are added or deleted. You may need to establish a new class w
2 min read
new and delete Operators in C++ For Dynamic Memory In C++, when a variable is declared, the compiler automatically reserves memory for it based on its data type. This memory is allocated in the program's stack memory at compilation of the program. Once allocated, it cannot be deleted or changed in size. However, C++ offers manual low-level memory ma
6 min read