为什么我们复制然后移动? [英] Why do we copy then move?

查看:99
本文介绍了为什么我们复制然后移动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在某处看到代码,其中某人决定复制对象,然后将其移动到类的数据成员。这让我困惑,因为我认为移动的整个要点是避免复制。下面是示例:

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

以下是我的问题:




  • 为什么我们不是对 str 进行右值引用?

  • ,特别是给予 std :: string

  • 的原因是作者决定制作副本的原因


解决方案

在我回答你的问题之前,有一件你似乎错了:以C ++ 11的价值取得并不总是意味着复制。如果传递一个右值,那么它将被移动(假设存在可行的移动构造函数),而不是被复制。 std :: string 有一个移动构造函数。



与C ++ 03不同, 11通常是通过价值取参数,因为我将在下面解释的原因。另请参阅 StackOverflow上的此问答


为什么我们不把参考值引用到 str


因为这将使得不可能传递左值,例如: / p>

  std :: string s =Hello; 
S obj(s); // s是一个左值,这将不会编译!

如果 S 只有一个构造函数接受


复制不会很昂贵,特别是像 std: :string


如果传递右值,到 str ,并且最终会被移动到 data 。不会执行复制。如果你传递一个左值,另一方面,左值将被复制到 str ,然后移动到数据



因此,总结一下,对于右值有两个移动,一个副本,一个移动。


作者决定复制,然后移动的原因是什么?


首先,如上所述,第一个并不总是一个副本;并且这说,答案是:因为它是高效的( std :: string 对象是便宜的)和简单



假设移动是便宜的(在这里忽略SSO),当考虑这个设计的整体效率时,它们几乎可以忽略。如果我们这样做,我们有一个副本的左值(如果我们将接受一个左值引用 const )和没有副本的右值(我们仍然有一个复制如果我们接受对 const 的左值引用。



这意味着,当提供左值时,通过左值引用 const



PS:上下文,我相信这是Q& A < a> OP是指。


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?

解决方案

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.

这篇关于为什么我们复制然后移动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆