2

Consider following code:

class Base {
public:
    int bi;
    Base() : bi(100)    {std::cout << "\nBase default constructor ...";}
    Base(int i) : bi(i) {std::cout << "\nBase int constructor: "<< bi;}
    Base(const Base& b) {std::cout << "\nBase copy constructor";}
    Base(Base&& b)      {std::cout << "\nBase move constructor";}
};

Base getBase() {
    cout << "\nIn getBase()";
    return Base();  
}
int main() {
    Base b2(getBase());  
    Base b3 = Base(2);   
    Base b4 = getBase(); 
}

In spite of rvalues being given, none of the above constructions in main are calling the move constructor. Is there a way to ensure that user defined move constructor is called?

Here is what I am getting:

In getBase()    
Base default constructor ...
Base int constructor: 2
In getBase()
Base default constructor ...
Base destructor: 100
Base destructor: 2
Base destructor: 100
DKR
  • 53
  • 7
  • before someone else give good answer, check this out http://en.cppreference.com/w/cpp/utility/move – Marson Mao Aug 31 '15 at 09:14
  • calling the move constructor is simply optimized away. "Copy elision" is your friend! – Klaus Aug 31 '15 at 09:17
  • 1
    Looks like `getBase()` is being inlined - try building that in its own translation unit and then linking. – Toby Speight Aug 31 '15 at 09:23
  • `@TobySpeight` That is giving a Segmentation fault! – DKR Aug 31 '15 at 09:58
  • `@Klaus` This was my point; how I can I force the call to move constructor? std::move() is one way. – DKR Aug 31 '15 at 10:12
  • @DKR you mean you wanted to know ways other than `std::move()`? – Marson Mao Aug 31 '15 at 10:14
  • `@MarsonMao` you already mentioned that in first comment. This [link](http://stackoverflow.com/a/19500502) tells that move will generate rvalue. The same I intended in my code but that got optimized away. Does it mean that the calls in my code are not resulting in rvalue? – DKR Aug 31 '15 at 11:09
  • @DKR I managed to understand what you were thinking. The question was marked as duplicate so that I can only answer here. Try the code below and you can see the move constructor being called. `Base1 operator + (const Base1& other) { int me = bi; int it = other.bi; Base1 next(me + it); return next; }`. Then make an object like `Base1 b6 = b1 + b2;`. I guess the point is to force a temporary object so that return value optimization has no chance to interfere . – Marson Mao Sep 01 '15 at 06:25
  • `@MarsonMao` Your code also resulting into RVO. Here is the output: `Base default constructor ... Base default constructor ... In operator+ Base int constructor: 200 ` – DKR Sep 02 '15 at 07:01
  • `@MarsonMao` can you do something now to un-mark it as duplicate? – DKR Sep 02 '15 at 07:01

1 Answers1

0

You can use std::move() method:

Base b4 = std::move(getBase());

This ensures that move constructor is called, but in this line it prevents copy-elision to optimalize copy constructor out of there. There is no need to call any constructor, so this is more example how to not use std::move().

Ormei
  • 91
  • 5
  • 3
    `getBase()` is already a prvalue, and you prevent copy-elision to happen – Piotr Skotnicki Aug 31 '15 at 09:18
  • 1
    @Ormei, instead of referring to the comments, perhaps you could explain this directly in the answer? – Aaron McDaid Aug 31 '15 at 09:32
  • `@PiotrSkotnicki` if `getBase()` is already a prvalue than why the move constructor is not being called? – DKR Sep 02 '15 at 07:14
  • When you write `Base b4 = getBase();`, copy-elision optimalizes the code to construct `Base` object right on place of `b4`, so there is no copy or move constructors called at all. – Ormei Sep 02 '15 at 08:56
  • `@Ormei` can you suggest any other way also to deliberately call move constructor? – DKR Sep 02 '15 at 10:32
  • `std::move` is pretty much all you need to call move constructor, only it should be called in different context. Consider `Base b4` has lots of data allocated in some containers inside and you want to push it into vector, `vector vb; ... vb.push_back(std::move(b4));`. This can save a lot of time and space. PS: If you are pushing rvalue, vector calls automaticaly move constructor. – Ormei Sep 02 '15 at 12:19