Strahinja Ajvaz
Strahinja Ajvaz

Reputation: 2633

why use a move constructor?

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

Answers (3)

VLL
VLL

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

marcinj
marcinj

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

Dietmar Kühl
Dietmar Kühl

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

Related Questions