Course Content
C++ Smart Pointers
C++ Smart Pointers
Providing Custom Deleters For Smart Pointers
We already know that smart pointers can automatically call the destructors of the dynamic objects when the objects are no longer needed. But what if we wanted to call a different function to destroy a dynamic object and properly clean the allocated memory? This is where custom deleters come into play.
What are custom deleters?
A Custom deleter is a function or a function object that is associated with a smart pointer during its creation. It defines how the pointed-to object should be destroyed when the smart pointer goes out of scope. Custom deleters enable more granular control over the resource cleanup process. This behavior allows developers to efficiently deallocate memory for a wide array of resources, including file handles, connections, and custom data structures.
Practical use cases
Let's consider a practical example to realize the importance of custom deleters. Suppose you are working on a project that involves handling files with smart pointers. You want to ensure that when a smart pointer goes out of scope, it also closes the associated file. This will ensure two things: the dynamic memory is deallocated AND the file is properly closed at the same time. Here’s how we can do both with a custom deleter:
main
#include <iostream> #include <memory> #include <fstream> void customFileDeleter(std::ofstream* file) { //check if file object is accessible and file is open if (file && file->is_open()) { file->close(); // Close the file } delete file; // Release memory } int main() { // Creating a smart pointer to a file with a custom deleter std::unique_ptr<std::ofstream, decltype(&customFileDeleter)> filePtr(new std::ofstream("example.txt"), &customFileDeleter); if (filePtr->is_open()) { *filePtr << "Writing to the file using a smart pointer with a custom deleter!\n"; } else { std::cout << "Failed to open the file!\n"; } // Smart pointer automatically closes the file when it goes out of scope }
While creating the unique pointer, we pass the customFileDeleter
function, our custom deleter, as a template parameter. The decltype
keyword is just used to extract the type of the function at compile time. The customFileDeleter
function allows us to combine memory deallocation and file closure inside a single function.
Shared pointers and custom deleters
To associate a custom deleter with a shared pointer, we have to pass the deleter to the constructor of the shared pointer. Let’s look at a simple example:
main
#include <iostream> #include <memory> // Custom deleter function for a resource void customResourceDeleter(int* ptr) { std::cout << "Custom deleter called for resource at address: " << ptr << std::endl; delete ptr; } int main() { // Creating a shared pointer with a custom deleter std::shared_ptr<int> sharedPtrWithCustomDeleter(new int(42), customResourceDeleter); // Accessing the shared resource std::cout << "Shared pointer value: " << *sharedPtrWithCustomDeleter << std::endl; // The shared pointer automatically manages the resource using the custom deleter }
In the above example, we are creating a shared pointer to an integer and passing the custom deleter function as an argument to the constructor.
Thanks for your feedback!