3

Here is the sample code:

using namespace std;
struct A {
    A(unique_ptr<int> s)
    : _s(move(s)){}

    unique_ptr<int> _s;
};

int main(int argc, const char * argv[]) {

    auto&& ptr = make_unique<int>(5);
    A a{ptr}; // Error
    A b{move(ptr)}; // OK 
    return 0;
}

My first guess was it should work without using 'move', but I get 'Call to implicitly deleted copy constructor' on clang. Perhaps the type of 'ptr' is not rvalue (strangely?)? Could someone clarify on this?

StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
user1668604
  • 413
  • 2
  • 10
  • Possible duplicate of [How do I pass a unique\_ptr argument to a constructor or a function?](https://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function) – acraig5075 Oct 17 '17 at 07:19

2 Answers2

5

There are several things at play here, most of them involving the phrasing of the standard for the various parts in the value category taxonomy. But here's the gist of it:

The deduction for ptr's type will follow the rules for forwarding references. So yes, it will be unique_ptr<int>&&. But ptr is not an rvalue. That's the tricky thing to understand. It's a reference you've bound to an rvalue, sure, but now the object is no longer unnamed, and nor is the reference to it.

It's now an object with a name. Intuitively, since you can assign to it, it's an lvalue (in the general sense). As such, it won't bind to an rvalue reference by itself. So you end up attempting to call the copy constructor.

To move it, you'd need to transform it into an expiring value again (from the type system's point of view). That's what std::move does by returning an (unnamed) rvalue reference to it.

StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
1

Either pass an r-value:

A a{ make_unique<int>(5) };

or std::move an l-value

auto ptr = make_unique<int>(5);
A b{ move(ptr) };
acraig5075
  • 9,913
  • 3
  • 29
  • 45