In this article we will discuss how to use custom deleter with std::shared_ptr.
When a shared_ptr object goes out of scope, its destructor is called. Inside its destructor it decrements the reference count by 1 and if new value of reference count is 0 then it deletes the associated raw pointer.
To delete the internal raw pointer in destructor, by default shared_ptr calls the delete() function i.e.
delete Pointer;
But its not always that we want to use delete function in destruction, there can be other requirements too like,
Frequently Asked:
If shared_ptr object points to an array instead of a simple pointer,
std::shared_ptr<int> p3(new int[12]);
In its destructor shared_ptr will try to delete the int array i.e. int [] by calling
delete
function, whereas as correct way is using
delete []
Adding custom deleter to shared_ptr<>
In such case we can pass a callback to shared_ptr’s constructor, that will be called from its destructor for deletion i.e.
Custom Deleter as function Pointer
// function that calls the delete [] on received pointer void deleter(Sample * x) { std::cout << "DELETER FUNCTION CALLED\n"; delete[] x; }
Pass the function pointer in constructor of shared_ptr to provide custom deleter i.e.
Best Resources to Learn C++:
// Creating a shared+ptr with custom deleter std::shared_ptr<Sample> p3(new Sample[12], deleter);
Check complete example as follows,
#include <iostream> #include <memory> struct Sample { Sample() { std::cout << "CONSTRUCTOR\n"; } ~Sample() { std::cout << "DESTRUCTOR\n"; } }; // function that calls the delete [] on received pointer void deleter(Sample * x) { std::cout << "DELETER FUNCTION CALLED\n"; delete[] x; } int main() { // Creating a shared+ptr with custom deleter std::shared_ptr<Sample> p3(new Sample[12], deleter); return 0; }
Ouput:
CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR DELETER FUNCTION CALLED DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR
Custom Deleter as Lambda Function or Function Object
We can also attach Function objects and Lambda functions as callback i.e.,
class Deleter { public: void operator() (Sample * x) { std::cout<<"DELETER FUNCTION CALLED\n"; delete[] x; } }; // Function Object as deleter std::shared_ptr<Sample> p3(new Sample[12], Deleter()); // Lambda function as deleter std::shared_ptr<Sample> p4(new Sample[12], [](Sample * x){ std::cout<<"DELETER FUNCTION CALLED\n"; delete[] x; });
There might be other cases when we don’t need to delete any memory we just need to releasing memory or resources to a pool etc.
Check out an example with dummy implementation of Memory Pool and Custom Deletor.
#include <iostream> #include <memory> struct Sample { }; // Memory Pool Dummy Kind of Implementation template<typename T> class MemoryPool { public: T * AquireMemory() { std::cout << "AQUIRING MEMORY\n"; return (new T()); } void ReleaseMemory(T * ptr) { std::cout << "RELEASE MEMORY\n"; delete ptr; } }; int main() { std::shared_ptr<MemoryPool<Sample> > memoryPoolPtr = std::make_shared< MemoryPool<Sample> >(); std::shared_ptr<Sample> p3(memoryPoolPtr->AquireMemory(), std::bind(&MemoryPool<Sample>::ReleaseMemory, memoryPoolPtr, std::placeholders::_1)); return 0; }
Output:
AQUIRING MEMORY RELEASE MEMORY
Ambiguous topic cleared in a nice way…Thank you.
awesome