3

I'm trying to construct an object from a function and later pass it to a function that uses it (and consumes it). Here's the code

std::unique_ptr<Object> createObject() {
  auto myobj = std::make_unique<Object>();
  .. modify myobj ..
  return std::move(myobj);
}

void consumeObject(std::unique_ptr<Object>&& robj) {
  myvector.emplace_back(std::forward<std::unique_ptr<Object>>(robj));
}


consumeObject(createObject()); // Is this right?

I'm not using rvalue references directly from the createObject since I would return a reference to deallocated memory.

Is std::move necessary in the part indicated in the code? What happens if, like I did in the code above, I pass a rvalue to be bound to the rvalue reference? The code seems to compile just fine but I can't see the difference between a

consumeObject(createObject());

and

consumeObject(std::move(createObject()));
Dean
  • 6,610
  • 6
  • 40
  • 90

2 Answers2

8

std::move doesn't do anything magic, it just casts the argument to an rvalue.

Since createObject returns by value, createObject() is already an rvalue (specifically a prvalue), so std::move is unnecessary in this case and you can safely omit it.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
3
std::unique_ptr<Object> createObject() {
  auto myobj = std::make_unique<Object>();
  .. modify myobj ..
  return std::move(myobj);
}

You don't need std::move to return a local, move-only object by value.

void consumeObject(std::unique_ptr<Object>&& robj) {
  myvector.emplace_back(std::forward<std::unique_ptr<Object>>(robj));
}

It doesn't make sense* to use std::forward except when you're using so-called "forwarding references", which you're not here. Just having && doesn't mean you should use std::forward. Also you don't need && here at all.

consumeObject(createObject()); // Is this right?

Yes.


Here's what the code probably should look like instead. Note that you mostly avoid any C++11 specific syntax and instead the code looks pretty much the same as passing a copyable object around by value. There's only one place here that anything new is necessary.

std::unique_ptr<Object> createObject() {
  auto myobj = std::make_unique<Object>();
  .. modify myobj ..
  return myobj;
}

void consumeObject(std::unique_ptr<Object> robj) {
  myvector.emplace_back(std::move(robj));
}


consumeObject(createObject());

* Both std::forward and std::move are just casts and the way you use std::forward here happens to work out to the correct cast to get a move construction. However for the sake of readability one should only use std::move to move and only use std::forward to forward.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • Thanks, also a follow-up (different question): http://stackoverflow.com/questions/33997586/use-of-stdmove-in-parameter-construction/ – Dean Nov 30 '15 at 13:17