2

In following case where i have created move ctor in Integer class, i am expecting that it should be called by default on rvalue reference while creating Product object but i am getting call of copy constructor only. Gcc - 7.5.0 on Ubuntu 18

#include<iostream> using namespace std; class Integer { int *dInt = nullptr; public: Integer(int xInt) { dInt = new int(xInt); cout<<"Integer Created"<<endl; } Integer(const Integer &xObj) { cout<<"Copy called"<<endl; dInt = new int(xObj.mGetInt()); } Integer(Integer &&xObj) { cout<<"Move called"<<endl; dInt = xObj.dInt; xObj.dInt = nullptr; } Integer& operator=(const Integer &xObj) { cout<<"Assignment operator called"<<endl; *dInt = xObj.mGetInt(); return *this; } Integer& operator=(Integer &&xObj) { cout<<"Move Assignment operator called"<<endl; delete dInt; dInt = xObj.dInt; xObj.dInt = nullptr; return *this; } ~Integer() { cout<<"Integer destroyed"<<endl; delete dInt; } int mGetInt() const {return *dInt;} }; class Product { Integer dId; public: Product(Integer &&xId) :dId(xId) { } }; int main () { Product P(10); // Notice implicit conversion of 10 to Integer obj. } 

In above case, move called if i use dId(std::move(xId)) in Product class ctor, I was expecting it should called by default on rvalue reference. In following case i couldn't avoid creating of temporary object of Integer class, Is there any good way to avoid creating of temporary object.

 Product(const Integer &xId) :dId(xId) { } Product(10); // inside main 

My purpose of above question to build my understanding so that i can utilize temporary object memory better.

2
  • Side note: Your class doesn't seem to need an int*. Consider just using an int member, or perhaps, a std::optional<int>, if you need to track that there is no int whatsoever (which you do now with a nullptr). Commented Aug 1, 2020 at 12:12
  • 1
    This was to build my understanding around move. Commented Aug 1, 2020 at 12:15

1 Answer 1

3

You need std::move to "propagate" rvalue-reference-ness.

Inside the body of the following function:

void foo(int&& x); 

…an expression x is an lvalue int. Not int&&.

References don't really "exist" — even though they are powered by the type system, they are supposed to be treated as aliases (rather than separate entities), so using x inside foo is treated just like using the original, referred-to int inside foo … and doing that would also create a copy, as you know.


This will do the job:

Product(Integer&& xId) : dId(std::move(xId)) {} 

However, I actually encourage you to take Integer by value:

Product(Integer xId) : dId(std::move(xId)) {} 

That way, you can use the same constructor for passing lvalue Integer too, and a copy will be produced if necessary, whereas a move will happen automatically if not (e.g. by passing in a literal, which will automatically trigger selection of Integer's move constructor).

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.