Take the 2-minute tour ×

In C++11 we can define copy and move constructors, but are both allowed on the same class? If so, how do you disambiguate their usage? For example:

Foo MoveAFoo() {
  Foo f;
  return f;

Is the above a copy? A move? How do I know?

share|improve this question
Yes, both copy and move constructors are allowed on the same class. The Rule of Three has become the Rule of Five. –  Ben Voigt Feb 5 '12 at 20:41
@BenVoigt Looks like an update to the corresponding Wikipedia article is in order ;) –  void.pointer Feb 5 '12 at 21:27

5 Answers 5

up vote 21 down vote accepted

Usually it will be neither due to RVO.

If that optimisation can't be performed, then it will be a move, because the object being returned is going out of scope (and will be destroyed just after). If it can't be moved, then it will be copied. If it can't be copied, it won't compile.

The whole point of move constructors is that when a copy is going to be made of an object that is just about to be destroyed, it is often unnecessary to make a whole copy, and the resources can be moved from the dying object to the object being created instead.

You can tell when either the copy or move constructor is going to be called based on what is about to happen to the object being moved/copied. Is it about to go out of scope and be destructed? If so, the move constructor will be called. If not, the copy constructor.

Naturally, this means you may have both a move constructor and copy constructor in the same class. You can also have a copy assignment operator and a move assignment operator as well.

Update: It may be unclear as to exactly when the move constructor/assignment operator is called versus the plain copy constructor/assignment operator. If I understand correctly, the move constructor is called if an object is initialised with an xvalue (eXpiring value). §3.10.1 of the standard says

An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

And the beginning of §5 of the standard says:

[ Note: An expression is an xvalue if it is:

  • the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,
  • a cast to an rvalue reference to object type,
  • a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or
  • a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not. —end note ]

As an example, if NRVO can be done, it's like this:

void MoveAFoo(Foo* f) {
    new (f) Foo;

Foo myfoo; // pretend this isn't default constructed

If NRVO can't be done but Foo is moveable, then your example is a little like this:

void MoveAFoo(Foo* fparam) {
    Foo f;

    new (fparam) Foo(std::move(f));

Foo f; // pretend this isn't being default constructed

And if it can't be moved but it can be copied, then it's like this

void MoveAFoo(Foo* fparam) {
    Foo f;

    new (fparam) Foo((Foo&)f);

Foo f; // pretend this isn't default constructed
share|improve this answer
You describe that the move constructor is chosen if the compiler detects that the source lvalue will be discarded shortly thereafter. Is this defined in the standard (possibly in Xeo's quote of the C++ standard)? It seems a bit hard to detect such a case. Could you emphasize a bit more on this? Xeo's quote of the standard makes it sound like the move constructor is ALWAYS chosen first, and only upon it not matching or existing will the copy constructor be chosen. –  void.pointer Feb 5 '12 at 21:24
@Robert: You dismiss the very first sentence of my quote - "When the criteria for copy elision are met". –  Xeo Feb 5 '12 at 21:28
@RobertDailey As for the compiler detecting when to use the move constructor, it does so when an object is being initialised with an x-value (eXpiring value) –  Seth Carnegie Feb 5 '12 at 21:30
@Xeo Not dismissed, just not understood. Your quote of the C++ standard is, for all intents and purposes, spoken in a different language. –  void.pointer Feb 5 '12 at 21:32
@SethCarnegie And I assume "x-value" requirements are defined by the C++11 standard as well? Or is this implementation-defined? –  void.pointer Feb 5 '12 at 21:33

To back up @Seth, here's the relevant paragraph from the standard:

§12.8 [class.copy] p32

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, 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. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]

share|improve this answer
+1 for standard quote –  Seth Carnegie Feb 5 '12 at 21:01
I've read this like 10 times but I still don't quite grasp what it is saying. This is why I can't really depend on the C++ standard for an understanding of this, unfortunately. The language of the standard is too "cryptic". –  void.pointer Feb 5 '12 at 21:22
@Robert: Well, that part first describes situations where copy elision is applicable. One of those is function return values. Then this part says, that an object like X& obj will first be tried to move (as X&&), and if that fails, it'll be tried to copy as X&, regardless if copy elision actually happens. –  Xeo Feb 5 '12 at 21:26
@Xeo I didn't see anything in there about return values. What part specifically are you translating? –  void.pointer Feb 5 '12 at 21:32
@Robert: The part of where copy elision is allowed is not included here. It's quite a long list, so I'm reluctant to just copy and paste it in here... You can however look for yourself in the N3337 paper (which is basically the standard) under 12.8/31. –  Xeo Feb 5 '12 at 21:50
Foo MoveAFoo() {
  Foo f;
  return f;

This is definition of function MoveAFoo that returns object of type Foo. In its body local Foo f; is created and destructed when it goes out of its scope.

In this code:

Foo x = MoveAFoo();

object Foo f; is created inside of MoveAFoo function and directly assigned into x, which means that copy constructor is not called.

But in this code:

Foo x;
x = MoveAFoo();

object Foo f; is created inside of MoveAFoo function, then the copy of f is created and stored into x and original f is destructed.

share|improve this answer
In the last example, the original Foo x; creates x. Then in when the statement x = MoveAFoo(); is performed, the value Foo() is moved into x (or there is move elision), which results in the value of f swapped with the value of x. The last operation cases the original x value being destroyed. There is no copying here! –  Mikhail Semenov Apr 13 '14 at 11:04

The "disambiguation" is just your old friend, overload resolution:

Foo y;

Foo x(y);            // copy
Foo x(std::move(y)); // move

The expression y in the first example is an lvalue of type Foo, which binds to Foo const & (and also Foo & if you have such a constructor); the type of the expression std::move(y) in the second example is Foo &&, so it'll bind to Foo && (and also Foo const & absent the former).

In your example, the result of MoveAFoo() is a temporary of type Foo, so it'll bind to the Foo &&-constructor if one is available, and to a const-copy constructor otherwise.

Finally, in a function returning Foo (by value), the statement return x; is equivalent to return std::move(x); if x is a local variable of type Foo -- this is a special new rule to make the use of move semantics easier.

share|improve this answer
static_assert( not std::is_same<decltype(MoveAFoo()), Foo&&>::value, "the type of MoveAFoo() is not Foo&&"); –  R. Martinho Fernandes Feb 5 '12 at 20:55
This isn't strictly correct. std::move(y) is indeed Foo&&, but MoveAFoo() is Foo. They are of two different value categories- one is xvalue and the other is prvalue, I believe. Whilst they are both rvalues, it is not correct to say that MoveAFoo() returns a Foo&&. You have made a similar mistake by stating that the type of y is Foo& - it is not. It is an lvalue of type Foo. –  Puppy Feb 5 '12 at 20:56
Ah, sorry, the same goes for y being Foo& :) –  R. Martinho Fernandes Feb 5 '12 at 20:58

The key difference between a copy and move constructor is that, by definition, a copy constructor leaves the source object intact. A move constructor would set the source object to its default state/value. Neither is killing/destroying the source object. Of course, a specific implementation does not have to follow this default behavior. Although this depends on implementation, typically, after a move constructor, the internal source object´s pointers are set to null, counters of the number of elements in arrays are set to 0 and so on.

Although a move constructor is preferable, a compiler must ensure that by using a move constructor instead of a copy constructor no bug is introduced. For example, if we have a situation where after an ambiguous constructor, we need to change the value of an element in an array that belongs to the instance of the source class, it is probably not possible to use a move constructor to resolve ambiguity, because by the default implementation, we are not going to find that element in an empty array in the source class after the move constructor.

In essence, although not destroyed, after a move constructor the source object is "dead" before being completely killed off, and it is better if we define its state as "undefined". A move constructor can be forced, however forcing the usage of this "dead" object after the forced move constructor, without considering its changed state, will most probably lead to an error.

However, in reality, the case might be that only some critical resources are moved over and set to default values in the source class, not all of the fields. Based on this, the source object after a forced move constructor should be best regarded as "undefined".

These source objects do not have to be spelled out. They are frequently hidden. A typical example of a move constructor usage is


This is actually how this might be done internally:


r is a temporary object that is created and then at the end assigned to a. If we use a copy constructor b+c is created as r, then copied to a, then discarded. It is much better to use r as it is without doubling anything, so we just move all resources from r to a, and leave r as an empty shell that will be destroyed anyway, since it is an invisible temporary object.

A compiler can easily detect the situations like the one above.

share|improve this answer

Your Answer


