0

I am looking over the std::pair constructors and noticed that when I pass in the following example, the move on the std::unique_ptr works but the std::string does not get moved.

std::string my_str = std::string("Hello World!");
auto my_smartp = std::make_unique<const std::string>();

const std::string &my_str_ref = my_str;

// my_str_ref is fine, no move
// my_smartp is fine, no move

auto pair = std::pair<std::string, std::unique_ptr<const std::string>>(my_str_ref, std::move(my_smartp));

// my_str_ref is fine and was not moved
// my_smartp is has been moved to the std::pair

This makes no sense to me as the only constructor I can see valid for this example is (2), passing in two const references which, as far as I know, shouldn't trigger any move. Either they are both passed as temporary U1&& and U2&& or they are both passed as const references const T1& and const T2&.

I am using the latest clang if the implementation makes any difference.

  • Note that (3) takes more than just temporaries. Those are universal references; they can accept both lvalue and rvalue references (independently of one another) – Justin Jan 10 '18 at 21:04
  • Duplicate? https://stackoverflow.com/questions/39552272/is-there-a-difference-between-universal-references-and-forwarding-references – François Andrieux Jan 10 '18 at 21:04

1 Answers1

1

You are calling the 3.th constructor

template< class U1, class U2 >
pair( U1&& x, U2&& y );

U&& is forwarding reference and can bind to both: lvalues and rvalues.

my_str_ref is the lvalue

std::move(my_smartp) is the rvalue.

The U1 is deduced to std::string&. x is a lvalue reference: std::string& - so here the copy construct get's called.

The U2 is deduced to std::unique_ptr<const std::string>. y is a rvalue ref: std::unqiue_ptr<const std::string>&&.

So pair.first gets copy-constructed from my_str_ref, pair.second gets move constrycted from my_smarp

llllllllll
  • 16,169
  • 4
  • 31
  • 54
StPiere
  • 4,113
  • 15
  • 24