I was recently introduced to this mechanism of using a std::unique_ptr
to implement a "generic" RAII mechanism:
// main.cpp
#include <memory>
#include <sys/fcntl.h>
#include <unistd.h>
#define RAII_CAT(x) raii ## x
#define RAII_CAT2(x) RAII_CAT(x)
#define RAII_FD(X) \
std::unique_ptr<int, void(*)(int*)> RAII_CAT2(__LINE__){X, [](int* x){ if (-1 != *x) { close(*x); }}}
int main(int argc, char* argv[]) {
{
int fd = open("foo.txt", O_RDONLY);
RAII_FD(&fd);
}
end:
return 0;
}
In the above code, the RAII_FD
macro creates a std::unique_ptr
object whose custom deleter takes an int*
-- the pointer to a file-descriptor -- and calls close()
on the file-descriptor.
I like this mechanism a lot, but I have a minor gripe that the custom deleter requires a pointer as its argument: aesthetically it feels a bit less than desirable.
E.g. in the code above, the custom deleter is a thin wrapper over int close(int)
-- it would be nice, therefore, if the custom deleter could take an int
instead of an int*
...in which case perhaps a wrapper function wouldn't be necessary at all: perhaps a function pointer to int close(int)
itself could be supplied.
I.e. variations of the following were tried, trying to register a custom deleter with signature void func(int)
instead of void func(int*)
:
// main.cpp
#include <memory>
#include <sys/fcntl.h>
#include <unistd.h>
#define RAII_CAT(x) raii ## x
#define RAII_CAT2(x) RAII_CAT(x)
#define RAII_FD(X) \
std::unique_ptr<int, void(*)(int)> RAII_CAT2(__LINE__){X, [](int x){ if (-1 != x) { close(x); }}}
int main(int argc, char* argv[]) {
{
int fd = open("foo.txt", O_RDONLY);
RAII_FD(fd);
}
end:
return 0;
}
...the compile error was a vomit of stl errors that I perhaps don't grok 100%, but I think the gist is there are int*
/int
mismatches in the various template expansions.
Is there another similar mechanism by which one can implement a "generic" RAII mechanism with custom deleters whose argument doesn't necessarily need to be a pointer?
I'm open to learning about all possible solutions, but solutions that are actually usable in my target environment must be C++11 and non-Boost. Most preferable would be some similar "thin wrapper" over STL-native objects.