2

"Theory" question if you will.

In order to execute/make use of the move constructor in a class, do I always have to use std::move(...) to tell the compiler that I wish to 'move' an object rather than copy it?

Are there any cases where the compiler will invoke the move constructor for me without the use of std::move? (My guess would be in function return values?)

2
  • iirc, throwing an exception is another example Commented Mar 6, 2016 at 18:22
  • @PiotrSkotnicki Can you explain that with more detail? Commented Mar 6, 2016 at 18:23

3 Answers 3

4

According to cppreference.com (http://en.cppreference.com/w/cpp/language/move_constructor):

The move constructor is called whenever an object is initialized from xvalue of the same type, which includes

  • initialization, T a = std::move(b); or T a(std::move(b));, where b is of type T;
  • function argument passing: f(std::move(a));, where a is of type T and f is void f(T t);
  • function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.

In most cases, yes std::move is needed.

Sign up to request clarification or add additional context in comments.

7 Comments

Ah, but not for function returns? My guess is correct?
@user3728501 If I understand what you're asking, it looks like the compiler will automatically invoke the move constructor.
ie; If I construct a std::vector in a function and return this vector, that is the same as return std::move(v); where v is that vector?
@user3728501 Yes (if you return it by value).
I guess returning a reference would be invalid anyway, since such a vector would be a temp object. If it wasn't (ie; passed as an argument) then I guess returning a reference would be an optimization anyway, so no reason to move anything.
|
4

The compiler will invoke the move constructor without std::move when:

  • returning a local variable by value
  • when constructing an object from an rvalue of the same type

In all other cases, use std::move. E.g.:

struct S {
  std::string name;
  S(std::string name) : name(std::move(name)) {}
};

and

std::unique_ptr<Base> func() {
  auto p = std::make_unique<Derived>();
  return std::move(p); // doesn't work without std::move
}

Comments

1

std::move is just a cast.

unique_ptr<int> global;

auto v = unique_ptr<int>(global); // global is a lvalue, therefore the
unique_ptr(unique_ptr<T>&v) constructor that accepts lvalue references is called.

auto v = unique_ptr<int>(std::move(global)); // move returns a &&rvalue reference, therefore the
unique_ptr(unique_ptr<T>&&v) constructor that accepts &&rvalue references is used.

When the criteria for elision of a copy operation are met and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

therefore,

unique_ptr<int> hello()
{
    unique_ptr<int> local;
    return local;

    // local is an lvalue, but since the critera for elision is met,
    // the returned object is created using local as if it was an rvalue
}

Also,

unique_ptr<int> hello = std::unique_ptr<int>();
// we have a pure rvalue in the right, therefore no std::move() cast is needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.