Home > Software engineering >  Why can't std::unique_ptr be returned after structured binding without using std::move?
Why can't std::unique_ptr be returned after structured binding without using std::move?

Time:12-09

When I try to compile the following code I get the error C2280. I guess the compiler is trying to copy the unique_ptr or something.

#include <memory>

std::pair<int, std::unique_ptr<int>> CreatePair()
{
    std::unique_ptr<int> my_int(new int);
    return { 1, std::move(my_int) };
}
std::unique_ptr<int> GetUinquePtr()
{
    auto [ignore, unique_ptr] = CreatePair();
    return unique_ptr; // <- Build error C2280 attempting to reference a deleted function
}
int main()
{
    auto unique_ptr = GetUinquePtr();
}

Complete error message:

error C2280: 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function

It works if I add std::move():

std::unique_ptr<int> GetUinquePtr()
{
    auto [ignore, unique_ptr] = CreatePair();
    return std::move(unique_ptr); // <- This works
}

And it works fine if I use std::tie:

std::unique_ptr<int> GetUinquePtr()
{
    std::unique_ptr<int> unique_ptr;
    std::tie(std::ignore, unique_ptr) = CreatePair();
    return unique_ptr; // <- This works
}

So do need to explicitly type std::move after structured binding of a unique_ptr or am I doing something wrong here?

CodePudding user response:

A structured binding creates references, and your code is more or less equivalent to this:

std::unique_ptr<int> GetUinquePtr()
{
    auto p = CreatePair();
    auto& ignore = p.first;
    auto& unique_ptr = p.second;
    return unique_ptr;
}

and returning the reference would create a copy.

With the tie, it works rather like this instead:

std::unique_ptr<int> GetUinquePtr()
{
    std::unique_ptr<int> unique_ptr;
    unique_ptr = CreatePair().second;
    return unique_ptr;
}

CodePudding user response:

A structured binding is not required to be of a reference type (but may). The copy elision of return value is non-mandatory.

Some other compiler is capable to elide it. Can be also MSVC is under certain compiling options.

So it seems to be within freedom given by standard and quality of implementation issue.

  • Related