In my previous article, we discussed how std::unique_ptr helps to avoid memory leak. By default it calls the default deleter (C++ delete operator) when the std::unique_ptr goes out of context. But many times default deleter is not good enough for the type of pointer we deal with. For example, if you work with a file pointer (std::FILE *), cleaning up memory does not mean to delete the pointer. You have to close the opened file. Forgetting to close a file is a very common programming mistake in C++. Default deleter does not close a file. Here you have to use your own custom deleter that will perform your custom operation like closing the file.
How to Provide Custom Deleter to std::pointer?
The std::unique_ptr constructor takes two arguments, 1) the pointer that it owns and manages, 2) optionally a deleter which is a function pointer or std::func object. If you don’t specify the second argument, it will use C++ delete operator as default deleter. You can specify your own function as deleter.
// File Name: test.cpp
// To compile: g++ test.cpp -std=c++11
#include <iostream>
#include <fstream>
#include <memory>
void close_file(std::FILE* fp) {
std::cout << "Closing file..." << std::endl;
std::fclose(fp);
}
int main() {
std::ofstream("myfile.txt") << "qnaplus.com";
std::unique_ptr<std::FILE, decltype(&close_file)> fp(std::fopen("myfile.txt", "r"), &close_file);
char str[16];
if(fp) {
std::cout << std::fgets(str, 16, fp.get()) << std::endl;
}
return 0;
}
Here, in time of creating the std::unique_ptr we provided a file pointer, fp, and our custom deleter function close_file(). When the std::unique_ptr will go out of context, the close_file() function will get called that will close the file. As we specified a custom deleter, default delete would not get called.
Lamda Function as Deleter
We can use a lamda function as deleter also. The same solution can be written as follows. This program and the above are basically same.
#include <iostream>
#include <fstream>
#include <memory>
int main() {
std::ofstream("myfile.txt") << "qnaplus.com";
std::unique_ptr<std::FILE, std::function<void(std::FILE *)>> fp(std::fopen("myfile.txt", "r"),
[](std::FILE *f){
std::cout << "Closing file..." << std::endl;
std::fclose(f);
});
char str[16];
if(fp) {
std::cout << std::fgets(str, 16, fp.get()) << std::endl;
}
return 0;
}