I happened to find a scenario where I am returning an object from a function by value.
With a conditional statement at the return statement, RVO is avoided.
Here is the code:
#include <iostream>
#include <cstring>
class myObject {
public:
myObject() {
std::cout <<"Default Constructor called" << std::endl;
buffer = new char[1000];
this->sz = 1000;
}
myObject(std::size_t sz) {
buffer = new char[sz];
this->sz = sz;
}
myObject(const myObject& other) {
std::cout <<"Copy Constructor called" << std::endl;
buffer = new char[other.sz];
sz = other.sz;
std::memcpy(buffer,other.buffer,other.sz);
}
myObject(myObject&& other) noexcept {
std::cout <<"Move Constructor called" << std::endl;
buffer = other.buffer;
sz = other.sz;
other.buffer = NULL;
other.sz = 0;
}
myObject& operator=(myObject&& other) noexcept {
std::cout <<"Move Assignment called" << std::endl;
if(buffer != NULL) {
delete[] buffer;
sz = 0;
}
buffer = other.buffer;
sz = other.sz;
other.buffer = NULL;
other.sz = 0;
return *this;
}
myObject& operator=(const myObject& other) {
// self ref ignored
std::cout <<"Copy Assignment called" << std::endl;
if(buffer != NULL) {
delete[] buffer;
sz = 0;
}
buffer = new char[other.sz];
sz = other.sz;
std::memcpy(buffer,other.buffer,other.sz);
return *this;
}
~myObject() {
std::cout <<"~myObject()" << std::endl;
if(buffer != NULL) {
delete[] buffer;
buffer = NULL;
}
}
char * buffer = NULL;
std::size_t sz = 0;
};
myObject GetObject_Complex(int x,int y) {
myObject obj;
myObject d;
return x > y ? obj : d; // intentionaly made conditional to avoid Return value optimization
}
int main() {
myObject c = GetObject_Complex(1,0); // Why move constructor is not called here ?
std::cout << std::endl << std::endl;
myObject d = std::move(c);
std::cout << std::endl << std::endl;
myObject e;
std::cout << std::endl << std::endl;
e = std::move(d);
}
Here the output using g++ -g -std=c++11
gcc version 7.5.0
Default Constructor called
Default Constructor called
Copy Constructor called
~myObject()
~myObject()
Move Constructor called
Default Constructor called
Move Assignment called
~myObject()
~myObject()
~myObject()
It seems that in the line myObject c = GetObject_Complex(1,0)
, copy operation is happening. But as per my understanding, when RVO is disabled and the object is defined with move operation, move constructor should be called.
Why move construction is not happening here? Am I missing something?
Thank You.
It seems that in the line
myObject c = GetObject_Complex(1,0)
, copy operation is happening.
Sort of but not quite. More accurately, the copy operation happens within GetObject_Complex
when the
result of the ternary conditional operator is copied to the temporary return value.
Why move construction is not happening here?
There is no move constructor because the compiler elided the move from the result of the function call as an optimisation.