rubix_addict
rubix_addict

Reputation: 1921

Why can't unique_ptr infer the type of the deleter?

Let's say I want to use a custom deleter with an unique_ptr:

void custom_deleter(int* obj)
{
    delete obj; 
}

Why do I have to write this:

std::unique_ptr<int, void(*)(int*)> x(new int, custom_deleter);

instead of this:

std::unique_ptr<int> x(new int, custom_deleter); //does not compile

?

Can't the type of the deleter be inferred?

Upvotes: 11

Views: 544

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275600

It cannot infer the type of the deleter, because unique_ptr by default has no state devoted to a deleter: the default deleter is stateless.

In your case, the deleter needs a pointer's worth of state, so it cannot 'fit' within the std::unique_ptr's state (which is just a pointer to a T).

This makes unique_ptr a lightweight, nearly cost-free replacement for an owning pointer.

Deductin could be done, but it would have to change the type of the resulting unique_ptr.

In comparison, shared_ptr always has state capacity for a deleter, two different atomic counters, and a pointer to value. It is heavier weight, and not a cost-free replacement for a pointer.

Upvotes: 3

Barry
Barry

Reputation: 303217

For unique_ptr, the deleter is part of the type:

template <
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;

As such, when you're constructing an object, you need to specify its type. The line you're writing:

std::unique_ptr<int> x(new int, custom_deleter);

is equivalent to:

std::unique_ptr<int, std::default_delete<int> > x(new int, custom_deleter);

And you cannot construct a std::default_delete<int> from custom_deleter.

The only way to infer the deleter type is to use template deduction on that part too:

template <typename T, typename Deleter>
std::unique_ptr<T, Deleter> make_unique_ptr(T* ptr, Deleter deleter) {
    return std::unique_ptr<T, Deleter>(ptr, deleter);
}

Upvotes: 6

Related Questions