Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
259 views
in Technique[技术] by (71.8m points)

c++ - Why does C++11 have implicit moves for value parameters, but not for rvalue parameters?

In C++11, value parameters (and other values) enjoy implicit move when returned:

A func(A a) {
    return a; // uses A::A(A&&) if it exists
}

At least in MSVC 2010, rvalue reference parameters need std::move:

A func(A && a) {
    return a; // uses A::A(A const&) even if A::A(A&&) exists
}

I would imagine that inside functions, an rvalue reference and a value behave similar, with the only difference that in case of values, the function itself is responsible for destruction, while for rvalue references, the responsibility is outside.

What is the motivation for treating them differently in the standard?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The standardization committee expended great effort in creating wording so that moves would only ever happen in exactly two circumstances:

  1. When it is clearly safe to do so.
  2. When the user explicitly asks (via std::move or a similar cast).

A value parameter will unquestionably be destroyed at the end of the function. Therefore, returning it by move is clearly safe; it can't be touched by other code after the return (not unless you're deliberately trying to break things, in which case you probably triggered undefined behavior). Therefore, it can be moved from in the return.

A && variable could be referring to a temporary. But it could be referring to an lvalue (a named variable). It is therefore not clearly safe to move from it; the original variable could be lurking around. And since you didn't explicitly ask to move from it (ie: you didn't call std::move in this function), no movement can take place.

The only time a && variable will be implicitly moved from (ie: without std::move) is when you return it. std::move<T> returns a T&&. It is legal for that return value to invoke the move constructor, because it is a return value.

Now it is very difficult to call A func(A &&a) with an lvalue without calling std::move (or an equivalent cast). So technically, it should be fine for parameters of && type to be implicitly moved from. But the standards committee wanted moves to be explicit for && types, just to make sure that movement didn't implicitly happen within the scope of this function. That is, it can't use outside-of-function knowledge about where the && comes from.

In general, you should only take parameters by && in two cases: either you're writing a move constructor (or move assignment operator, but even that can be done by value), or you're writing a forwarding function. There may be a few other cases, but you shouldn't take && to a type unless you have something special in mind. If A is a moveable type, then just take it by value.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...