Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using custom deleter with unique_ptr

With shared_ptr you can use a custom deleter, like:

auto fp = shared_ptr<FILE>( fopen("file.txt", "rt"), &fclose );
fprintf( fp.get(), "hello\n" );

and this will remember to fclose the file regardless of how the function exits.
However, it seems a bit overkill to refcount a local variable, so I want to use unique_ptr:

auto fp = unique_ptr<FILE>( fopen("file.txt", "rt"), &fclose );

however, that does not compile.

Is this a defect? Is there a simple workaround? Im I missing something trivial?

like image 962
sp2danny Avatar asked Oct 14 '14 12:10

sp2danny


People also ask

Does unique_ptr call Delete?

An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

Can you pass unique_ptr to a function?

Why can I not pass a unique_ptr into a function? You cannot do that because unique_ptr has a move constructor but not a copy constructor. According to the standard, when a move constructor is defined but a copy constructor is not defined, the copy constructor is deleted.

Why would you choose shared_ptr instead of unique_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

What happens when unique_ptr goes out of scope?

An​ unique_ptr has exclusive ownership of the object it points to and ​will destroy the object when the pointer goes out of scope. A unique_ptr explicitly prevents copying of its contained pointer. Instead, the std::move function has to be used to transfer ownership of the contained pointer to another unique_ptr .


2 Answers

Should be

unique_ptr<FILE, int(*)(FILE*)>(fopen("file.txt", "rt"), &fclose);

since http://en.cppreference.com/w/cpp/memory/unique_ptr

or, since you use C++11, you can use decltype

std::unique_ptr<FILE, decltype(&fclose)>
like image 113
ForEveR Avatar answered Sep 20 '22 19:09

ForEveR


The above answer while its intent is OK and in practice compiles and works is wrong, because it is not specified that you are allowed to take the address of a standard library function. A C++ library implementation is allowed to provide different overloads or more parameters (with default arguments). Only calling the library function is sanctioned by the standard. Therefore, you need to wrap the call to fclose in your own function implementation or lambda, such as

unique_ptr<FILE, int(*)(FILE*)>(fopen("file.txt", "rt"),
   [](FILE *fp)->int{ if(fp) return ::fclose(fp); return EOF;});

or wait for unique_resourceof https://wg21.link/p0052 to become standardized, but even there you need to use the lambda or a deleter function (object), see the more recent versions of p0052.

like image 42
PeterSom Avatar answered Sep 21 '22 19:09

PeterSom