Search code examples
c++11shared-ptrwofstreamwifstream

How to convert between shared_ptr<FILE> to FILE* in C++?


I am trying to use a FILE pointer multiple times through out my application for this I though I create a function and pass the pointer through that. Basically I have this bit of code

     FILE* fp;
    _wfopen_s (&fp, L"ftest.txt", L"r");
    _setmode (_fileno(fp), _O_U8TEXT);
    wifstream file(fp);

which is repeated and now instead I want to have something like this:

wifstream file(SetFilePointer(L"ftest.txt",L"r"));
....
wofstream output(SetFilePointer(L"flist.txt",L"w"));

and for the function :

FILE* SetFilePointer(const wchar_t* filePath, const wchar_t * openMode)
{
    shared_ptr<FILE> fp = make_shared<FILE>();
    _wfopen_s (fp.get(), L"ftest.txt", L"r");
    _setmode (_fileno(fp.get()), _O_U8TEXT);
    return fp.get();
}

this doesn't simply work. I tried using &*fp instead of fp.get() but still no luck.


Solution

  • You aren't supposed to create FILE instances with new and destroy them with delete, like make_shared does. Instead, FILEs are created with fopen (or in this case, _wfopen_s) and destroyed with fclose. These functions do the allocating and deallocating internally using some unspecified means.

    Note that _wfopen_s does not take a pointer but a pointer to pointer - it changes the pointer you gave it to point to the new FILE object it allocates. You cannot get the address of the pointer contained in shared_ptr to form a pointer-to-pointer to it, and this is a very good thing - it would horribly break the ownership semantics of shared_ptr and lead to memory leaks or worse.

    However, you can use shared_ptr to manage arbitrary "handle"-like types, as it can take a custom deleter object or function:

    FILE* tmp;
    shared_ptr<FILE> fp; 
    if(_wfopen_s(&tmp, L"ftest.txt", L"r") == 0) {
      // Note that we use the shared_ptr constructor, not make_shared
      fp = shared_ptr<FILE>(tmp, std::fclose);
    } else {
      // Remember to handle errors somehow!
    }
    

    Please do take a look at the link @KerrekSB gave, it covers this same idea with more detail.