Poperton
Poperton

Reputation: 2148

no instance of overloaded function "std::make_unique" matches the argument list, but works with unique_ptr constructor

If I do:

std::unique_ptr<AVFrame, AVFrameDeleter> avFrameUniquePtr(av_frame_alloc());

I get no errors. Observe that

av_frame_alloc() 

returns AVFrame*

However if I do

std::unique_ptr<AVFrame, AVFrameDeleter>  avFrameUniquePtr = std::make_unique<AVFrame,AVFrameDeleter>(av_frame_alloc());

I get

no instance of overloaded function "std::make_unique" matches the argument list -- argument types are: (AVFrame *)

For me it should be ok. What's happening?

Upvotes: 2

Views: 3041

Answers (2)

Qaz
Qaz

Reputation: 61910

make_unique is for allocating an object (forwarding its arguments through to the constructor) and returning a unique_ptr to that object. Since av_frame_alloc already allocates the object, there's no reason to allocate again.

What you want is exactly what the constructor of unique_ptr does—to take ownership of that pointer returned by av_frame_alloc. make_unique isn't the right tool for when you want to transfer ownership.

Now you mention in a comment that this is a class member. You can deal with that through braces (the language disallows parentheses in this context specifically) or the member initializer list of the constructors:

class Foo {
    // A
    std::unique_ptr<AVFrame, AVFrameDeleter> avFrameUniquePtr{av_frame_alloc()};

    // B
    std::unique_ptr<AVFrame, AVFrameDeleter> avFrameUniquePtr;
    Foo() : avFrameUniquePtr(av_frame_alloc()) {}
};

Upvotes: 3

songyuanyao
songyuanyao

Reputation: 172924

What's happening?

Unfortunately, std::make_unique can't specify the deleter type. Its 2nd template parameter is used for the type of the list of arguments passed to it. The code fails because you specify it as AVFrameDeleter explicitly, but pass AVFrame*, they don't match.

Unlike std::make_shared (which has std::allocate_shared), std::make_unique does not have an allocator-aware counterpart. A hypothetical allocate_unique would be required to invent the deleter type D for the unique_ptr<T,D> it returns which would contain an allocator object and invoke both destroy and deallocate in its operator().

On the other hand, the following code works (even it's not what you expect).

// the 1st template parameter is specified as AVFrame
// the 2nd template parameter is deduced as {AVFrame*}
// construct a std::unique_ptr<AVFrame, std::default_delete<AVFrame>>
std::make_unique<AVFrame>(av_frame_alloc()); 

Upvotes: 2

Related Questions