Reputation: 2633
I'm a little confused as to why you would use/need a move constructor.
If I have the following:
vector fill(istream& is)
{
vector res;
for(double x; is >> x; res.push_back(x));
return res;
}
void bar()
{
vector vec = fill(cin);
// ... use vec ...
}
I can remove the need to return res, hence not calling the copy constructor, by adding vector fill(istream& is, vector& res)
.
So what is the point of having a move constructor?
Upvotes: 1
Views: 441
Reputation: 10155
One reason is that using assignment operators makes it easier to grasp what each line is doing. If have a function call somefunction(var1, var2, var3)
, it is not clear whether some of them gets modified or not. To find that out, you have to actually read the other function.
Additionally, if you have to pass a vector as an argument to fill()
, it means every place that calls your function will require two lines instead of one: First to create an empty vector, and then to call fill()
.
Another reason is that a move constructor allows the function to return an instance of a class that does not have a default constructor. Consider the following example:
struct something{
something(int i) : value(i) {}
something(const something& a) : value(a.value) {}
int value;
};
something function1(){
return something(1);
}
void function2(something& other){
other.value = 2;
}
int main(void){
// valid usage
something var1(18);
// (do something with var1 and then re-use the variable)
var1 = function1();
// compile error
something var2;
function2(var2);
}
In case you are concerned about effiency, it should not matter whether you write your fill()
to return a value, or to take output variable as a parameter. Your compiler should optimize it to the most efficient alternative of those two. If you suspect it doesn't, you had better measure it.
Upvotes: 2
Reputation: 49976
In you example compiler might apply RVO - Return Value Optimization, this means you function will be inlined, so no return will take place - and no move semantics will be applied. Only if it cannot apply RVO - move constructor will be used (if available).
Before move semantics were introduced people were using various techniques to simulate them. One of them is actually returning values by references.
Upvotes: 2
Reputation: 153810
Assume you next put you std::vector<T>
into a std::vector<std::vector<T>>
(if you think vectors shouldn't be nested, assume the inner type to be std::string
and assume we are discussing std::string
's move constructor): even though you can add an empty object and fill it in-place, eventually the vector will need to be relocated upon resizing at which point moving the elements comes in handy.
Note that returning from a function isn't the main motivator of move construction, at least, not with respect to efficiency: where efficiency matters structuring the code to enable copy-elision further improves performance by even avoiding the move.
The move constructor may still be relevant semantically, though, because returning requires that a type is either copyable or movable. Some types, e.g., streams, are not copyable but they are movable and can be returned that way.
Upvotes: 4