8

C++11 introduced a new concept of rvalue reference. I was reading it somewhere and found following:

class Base
{
public:
    Base()  //Default Ctor
    Base(int t)  //Parameterized Ctor

    Base(const Base& b)  //Copy Ctor
    Base(Base&& b)  //Move Ctor
};

void foo(Base b)     //Function 1
{}

void foo(Base& b)   //Function 2
{}

int main()
{
    Base b(10);
    foo(b);        -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
    foo(Base());   -- Line 2
    foo(2) ;       -- Line 3
}

Now with my limited understanding, my observations are as follows :

  1. Line 1 will simply call the copy constructor as argument is an lvalue.

  2. Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.

  3. Line 3 will again call move constructor as 2 will be implicitly converted to Base type (rvalue).

Please correct and explain if any of above observation is wrong.

Now, here'r my questions :

  1. I know once we move an object it's data will be lost at calling location. So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).

  2. I have read move constructor is more efficient than copy constructor. How? I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?

  3. Is it even more efficient than passing by reference (no, right?)?

PaperBirdMaster
  • 11,602
  • 9
  • 41
  • 84
instance
  • 1,340
  • 13
  • 23
  • Your particular example has no data members, so *all* of those options can *do nothing*, and still behave correctly (the "as-if" rule) – Caleth Dec 19 '18 at 13:37

2 Answers2

9

First on your "understandings":

As I can see it, they are in principle right but you should be aware of Copy elision which could prevent the program from calling any copy/move Constructor. Depends on your compiler (-settings).

On your Questions:

  1. Yes you have to call foo(std::move(b)) to call an Function which takes an rvalue with an lvalue. std::move will do the cast. Note: std::move itself does not move anything.

  2. Using the move-constructor "might" be more efficient. In truth it only enables programmers to implement some more efficient Constructors. Example consider a vector which is a Class around a pointer to an array which holds the data (similar to std::vector), if you copy it you have to copy the data, if you move it you can just pass the pointer and set the old one to nullptr. But as I read in Effective Modern C++ by Scott Meyers: Do not think your program will be faster only because you use std::move everywere.

  3. That depends on the usage of the input. If you do not need a copy in the function it will in the most cases be more efficient to just pass the object by (const) reference. If you need a copy there are several ways of doing it for example the copy and swap idiom. But as a

Enlico
  • 12,203
  • 5
  • 28
  • 59
ab.o2c
  • 238
  • 3
  • 7
  • I would elaborate on point 3 that passing by reference causes dereference overhead when using the parameter, which can result in worse performance than copy/move, but it depends. Very good first answer! – slawekwin Dec 09 '16 at 07:39
  • 2
    I would finish the post! – underscore_d Dec 09 '16 at 09:23
3

Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.

Correct, except any decent optimizer would "elide" the copy, so that before C++11 the copy would have been avoided, and post C++11 the move would have been avoided. Same for line 3.


  1. I know once we move an object it's data will be lost at calling location.

Depends on how the move constructor/assignment is implemented. If you don't know, this is what you must assume.

So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).

Exactly. std::move changes the type of the expression into r-value and therefore the move constructor is invoked.

I have read move constructor is more efficient than copy constructor.

It can be, in some cases. For example the move constructor of std::vector is much faster than copy.

I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?

The statement isn't universally true, since for objects with trivial copy constructor, the move constructor isn't any more efficient. But owning dynamic memory isn't strictly a requirement for a more efficient move. More generally, move may can be efficient if the object owns any external resource, which could be dynamic memory, or it could be for example a reference counter or a file descriptor that must be released in the destructor and therefore re-aquired or re-calculated on copy - which can be avoided on move.

Is it even more efficient than passing by reference (no, right?)?

Indeed not. However, if you intend to move the object within the function where you pass it by reference, then you would have to pass a non-const reference and therefore not be able to pass temporaries.

In short: Reference is great for giving temporary access to an object that you keep, move is great for giving the ownership away.

eerorika
  • 181,943
  • 10
  • 144
  • 256