Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unique_ptr<> v shared_ptr<> in regards to destruction policy

Tags:

c++

c++11

I've been teaching myself the smart pointers that are part of C++0x and came across something that feels inconsistent to me. Specifically, how the destruction policy of unique_ptr<> and shared_ptr<> are handled.

For unique_ptr<>, you can specialize std::default_delete<> and from then on unless you explicitly request a different destruction policy, the new default will be used.

Consider the following:

struct some_c_type;

some_c_type *construct_some_c_type();
void destruct_some_c_type(some_c_type *);

namespace std  {
    template <> struct default_delete<some_c_type> {
        void operator()(some_c_type *ptr) {
            destruct_some_c_type(ptr);
        }
     };
}

Now, once that's in place, unique_ptr<> will use the appropriate destruction policy by default:

// Because of the specialization, this will use destruct_some_c_type
std::unique_ptr<some_c_type> var(construct_some_c_type());

Now compare this to shared_ptr<>. With shared_ptr<>, you need to explicitly request the appropriate destruction policy or it defaults to using operator delete:

// error, will use operator delete 
std::shared_ptr<some_c_type> var(construct_some_c_type());

// correct, must explicitly request the destruction policy
std::shared_ptr<some_c_type> var(construct_some_c_type(),
                                 std::default_delete<some_c_type>());

Two questions.

  1. Am I correct that shared_ptr<> requires the destruction policy to be specified every time it's used or am I missing something?
  2. If I'm not missing something, any idea why the two are different?

P.S. The reason I care about this is my company does a lot of mixed C and C++ programming. The C++ code often needs to use C-style objects so the ease of specifying a different default destruction policy is quite important to me.

like image 829
R Samuel Klatchko Avatar asked Feb 19 '10 23:02

R Samuel Klatchko


People also ask

Should I use shared_ptr or 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 is shared_ptr?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.

Can I convert shared_ptr to unique_ptr?

Afterword. The flawless conversion of an std::unique_ptr to a compatible std::shared_ptr makes it possible to write efficient and safe factory functions. However, note that an std::shared_ptr cannot be converted to an std::unique_ptr.

What is unique_ptr?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.


1 Answers

I think the question boils down to why std::shared_ptr can have no associated deleter (in which case it just calls delete) rather than constructing a std::default_delete by default. (No idea. If the intention was that default_delete is for specializing, one would expect it to be used by shared_ptr.)

Otherwise there are trade-offs.

It is better to have fewer template arguments. Boost's reference mentions that this allows a factory to change the allocation scheme without the change affecting the user of the factory.

A unique_ptr on the other hand is supposed to be very light-weight. How would you store the deleter with zero space overhead (in case of a functor without members) if it wasn't part of the type (GCC uses tuple, where memberless objects don't take memory space)?


Subjectively, I think I'd prefer:

unique_ptr<FILE, FCloser> f(fopen(x, y));

to

unique_ptr<FILE> f(fopen(x, y)); //default_delete<FILE> has been specialized

In the first case there's nothing to guess. If the resource does not come from new or new[], a deleter has to be explicitly given.

like image 90
UncleBens Avatar answered Oct 28 '22 23:10

UncleBens