I'm trying to understand move semantics and copy/move elision.
I would like a class that wraps up some data. I would like to pass the data in in the constructor and I would like to own the data.
After reading this, this and this I got the impression that in C++11 if I want to store a copy then pass-by-value should be at least as efficient as any other option (apart from the minor issue of increased code size).
Then if the calling code would like to avoid a copy, it can by passing an rvalue instead of an lvalue. (e.g using std::move)
So I tried it out:
#include <iostream>
struct Data {
Data() { std::cout << " constructor\n";}
Data(const Data& data) { std::cout << " copy constructor\n";}
Data(Data&& data) { std::cout << " move constructor\n";}
};
struct DataWrapperWithMove {
Data data_;
DataWrapperWithMove(Data&& data) : data_(std::move(data)) { }
};
struct DataWrapperByValue {
Data data_;
DataWrapperByValue(Data data) : data_(std::move(data)) { }
};
Data
function_returning_data() {
Data d;
return d;
}
int main() {
std::cout << "1. DataWrapperWithMove:\n";
Data d1;
DataWrapperWithMove a1(std::move(d1));
std::cout << "2. DataWrapperByValue:\n";
Data d2;
DataWrapperByValue a2(std::move(d2));
std::cout << "3. RVO:\n";
DataWrapperByValue a3(function_returning_data());
}
Output:
1. DataWrapperWithMove:
constructor
move constructor
2. DataWrapperByValue:
constructor
move constructor
move constructor
3. RVO:
constructor
move constructor
I was pleased that in none of these cases is a copy constructor called but why is there an extra move constructor called in the second case? I guess any decent move constructor for Data
should be pretty quick but it still niggles me. I am tempted to use pass-by-rvalue-reference (the first option) instead as this seems to result in one less move constructor call but I would like to embrace pass-by-value and copy elision if I can.