Even in the presence of <fstream>, there may be reason for using the <cstdio> file interface. I was wondering if wrapping a FILE* into a shared_ptr would be a useful construction, or if it has any dangerous pitfalls:
#include <cstdio>
#include <memory>
std::shared_ptr<std::FILE> make_file(const char * filename, const char * flags)
{
std::FILE * const fp = std::fopen(filename, flags);
return fp ? std::shared_ptr<std::FILE>(fp, std::fclose) : std::shared_ptr<std::FILE>();
}
int main()
{
auto fp = make_file("hello.txt", "wb");
fprintf(fp.get(), "Hello world.");
}
Update: I just realized that it is not allowed to fclose a null pointer. I modified make_file accordingly so that in the event of failure there won't be a special deleter.
Second update: I also realized that a unique_ptr might be a more suitable than shared_ptr. Here is a more general approach:
typedef std::unique_ptr<std::FILE, int (*)(std::FILE *)> unique_file_ptr;
typedef std::shared_ptr<std::FILE> shared_file_ptr;
static shared_file_ptr make_shared_file(const char * filename, const char * flags)
{
std::FILE * const fp = std::fopen(filename, flags);
return fp ? shared_file_ptr(fp, std::fclose) : shared_file_ptr();
}
static unique_file_ptr make_file(const char * filename, const char * flags)
{
return unique_file_ptr(std::fopen(filename, flags), std::fclose);
}
Edit. Unlike shared_ptr, unique_ptr only invokes the deleter if the pointer is non-zero, so we can simplify the implementation of make_file.
Third Update: It is possible to construct a shared pointer from a unique pointer:
unique_file_ptr up = make_file("thefile.txt", "r");
shared_file_ptr fp(up ? std::move(up) : nullptr); // don't forget to check
Fourth Update: A similar construction can be used for dlopen()/dlclose():
#include <dlfcn.h>
#include <memory>
typedef std::unique_ptr<void, int (*)(void *)> unique_library_ptr;
static unique_library_ptr make_library(const char * filename, int flags)
{
return unique_library_ptr(dlopen(filename, flags), dlclose);
}
printffor that purpose. Attempts to do that iniostreamslead to dramatic amounts of boilerplate code and it's never clear whether something will come out decimal or hex. Sofprintfit is :-) But I was just sort of curious in general whether this would be a useful and correct idiom. – Kerrek SB Sep 8 '11 at 13:48unique_ptrnot be a better choice? Are you really going to share it? – Loki Astari Sep 8 '11 at 15:21unique_ptris certainly an alternative... I just thought of another application: You can put those guys into a standard container and thus manage a collection of open files easily. – Kerrek SB Sep 8 '11 at 15:23unique_ptris better in the sense that it only invokes the deleter if the pointer is not null. Also, you can create a shared pointer from a unique one, but that opens up the problem of null pointer deletion. – Kerrek SB Nov 27 '11 at 2:24