0
#include <iostream>
static int i=0;
using namespace std;
class Movable
{
public:
    Movable ():mId(++i){
        cout<<"constructing it "<<mId<<endl;
    };
    Movable (const Movable&)=delete;
    Movable (Movable&)=delete;
    void operator=(Movable&)=delete;
    void operator=(const Movable&)=delete;

    Movable (const Movable&& aObject)
    {
        cout<<"Moving it constant "<<mId<<endl;
//      mId=++i;
    };
    Movable (Movable&&aObject)
    {
        cout<<"Moving it "<<mId<<endl;
    };
    Movable &operator=( Movable&&aObject)
    {
        cout<<"Moving it assignment "<<mId<<endl;
        return *this;

    }
    Movable &operator=(const Movable&&aObject)
    {
        cout<<"Moving it assignment constant "<<mId<<endl;
        return *this;

    }
    ~Movable ()
    {
        cout<<"destroying it "<<mId<<endl;
    }

    int getId() const {
        return mId;
    }

private:
    int mId;
};

Movable&& CreatenNewMovable ()
{
    Movable lM;
    return std::move(lM);
}

int main() {
    Movable a;

    a=CreatenNewMovable();

    return 0;
}

The output result of this code is

constructing it 1
constructing it 2
destroying it 2
Moving it assignment 1
destroying it 1

I'm a little bit confused how is it possible to destroy the temp object then move it to second. Is that an undefined behavior ? m I missing something about the move operation?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Anis Belaid
  • 304
  • 2
  • 8

2 Answers2

2

Yes, this function

Movable&& CreatenNewMovable ()
{
    Movable lM;
    return std::move(lM);
}

is broken.

An r-value reference is still a reference, in this case its a reference to a local stack object which is destroyed when the function terminates (before it is moved from). Instead you should just return it by value, it will still get moved out of and if there is copy-ellision then it will be efficient.

Chris Beck
  • 15,614
  • 4
  • 51
  • 87
  • I changed the function Movable CreatenNewMovable () { Movable lM; return lM; } the output is now constructing it 1 constructing it 2 Moving it assignment 1 destroying it 2 destroying it 1. that means that the object was moved then destructed. how is that different from the copy operation ? – Anis Belaid Sep 01 '15 at 16:40
  • 1
    It's only different if moving is implemented more efficiently than copying, for the class in question. In the case of e.g. a std::vector, the move operation is way more efficient because it doesn't allocate new memory and it doesn't copy or move all of the member objects -- the move works by "pilfering" the pointers owned by the object being moved from. – Chris Beck Sep 01 '15 at 17:27
  • You might want to look here: http://stackoverflow.com/questions/3106110/what-are-move-semantics?rq=1 and here: http://stackoverflow.com/questions/6943805/are-moved-from-objects-required-to-be-destructed?rq=1 – Chris Beck Sep 01 '15 at 17:41
2

Look at this snippet:

Movable&& CreatenNewMovable ()
{
    Movable lM;
    return std::move(lM);
}

Actually this is Undefined Behaviour. There are 2 problems:

  1. A function can return its value only by value (probably a reference value). So, you must replace Movable&& with Movable here.
  2. Creating Movable lM; on the stack and referencing it outside the function is UB. When the function exits, the object no longer exists. Return it simply by value - in your case copy elision will be in effect.

Finally, a valid way is :

Movable CreatenNewMovable ()
{
    Movable lM;
    return lM;
    // ..or..
    // Even better to return like this(copy elision has less chances to fail)
    // return Movable();
}

This will produce result you are waiting:

$ ./w 
constructing it 1
constructing it 2
Moving it assignment 1
destroying it 2
destroying it 1

You can reduce even this job by removing empty object creation in your main:

int main() {
    Movable a=CreatenNewMovable();
    return 0;
}
/* Results:
$ ./w
constructing it 1
destroying it 1
*/
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Galimov Albert
  • 7,269
  • 1
  • 24
  • 50