Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I saw code somewhere in which someone decided to copy an object and subsequently move it to a data member of a class. This left me in confusion in that I thought the whole point of moving was to avoid copying. Here is the example:

struct S
{
    S(std::string str) : data(std::move(str))
    {}
};

Here are my questions:

  • Why aren't we taking an rvalue-reference to str?
  • Won't a copy be expensive, especially given something like std::string?
  • What would be the reason for the author to decide to make a copy then a move?
  • When should I do this myself?
See Question&Answers more detail:os

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

1 Answer

Before I answer your questions, one thing you seem to be getting wrong: taking by value in C++11 does not always mean copying. If an rvalue is passed, that will be moved (provided a viable move constructor exists) rather than being copied. And std::string does have a move constructor.

Unlike in C++03, in C++11 it is often idiomatic to take parameters by value, for the reasons I am going to explain below. Also see this Q&A on StackOverflow for a more general set of guidelines on how to accept parameters.

Why aren't we taking an rvalue-reference to str?

Because that would make it impossible to pass lvalues, such as in:

std::string s = "Hello";
S obj(s); // s is an lvalue, this won't compile!

If S only had a constructor that accepts rvalues, the above would not compile.

Won't a copy be expensive, especially given something like std::string?

If you pass an rvalue, that will be moved into str, and that will eventually be moved into data. No copying will be performed. If you pass an lvalue, on the other hand, that lvalue will be copied into str, and then moved into data.

So to sum it up, two moves for rvalues, one copy and one move for lvalues.

What would be the reason for the author to decide to make a copy then a move?

First of all, as I mentioned above, the first one is not always a copy; and this said, the answer is: "Because it is efficient (moves of std::string objects are cheap) and simple".

Under the assumption that moves are cheap (ignoring SSO here), they can be practically disregarded when considering the overall efficiency of this design. If we do so, we have one copy for lvalues (as we would have if we accepted an lvalue reference to const) and no copies for rvalues (while we would still have a copy if we accepted an lvalue reference to const).

This means that taking by value is as good as taking by lvalue reference to const when lvalues are provided, and better when rvalues are provided.

P.S.: To provide some context, I believe this is the Q&A the OP is referring to.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...