这个复制值是两次吗?

Jac*_*ack 1 c++ windows qt copy c++11

我们假设我有一个这样的类:

class Foo
{
  public:
     QString a;
     void setA(QString val);
}
Run Code Online (Sandbox Code Playgroud)

并实现setA()如下:

void Foo::setA(QString val)
{
  this->a = val;
}
Run Code Online (Sandbox Code Playgroud)

并使用它像:

Foo f;
QString v = "foo";
f.setA(v);
Run Code Online (Sandbox Code Playgroud)

v在堆栈上复制结构两次吗?一个用于传递参数,另一个用于函数内的赋值,这是对的吗?通过使用,而void setA(QString &val);将避免复制对象两次,因为在第一次我只是复制引用(指针),而不是整个对象,以使对象的唯一副本是在分配:

  this->a = val;
Run Code Online (Sandbox Code Playgroud)

pep*_*ppe 7

我在堆栈上复制v struct两次吗?一个用于传递参数,另一个用于函数内的赋值,这是对的吗?

那就对了.您正在通过值传递,因此必须构造一个新对象(在您的情况下,通过复制构造函数).

现在,在QString(和Qt中的许多其他值类型)的特定情况下,该操作非常便宜,因为隐式共享 QString (读取:引用计数,写入时复制).在其他数据类型的情况下,操作可能是昂贵的.

通过使用void setA(QString&val)

或实际上通过使用setA(const QString &val),因为您没有修改引用的对象val.通过使用const引用,您还可以使用临时值:

void setA(QString &val);
setA(QString("foo")); // does not compile!

void setA(const QString &val);
setA(QString("foo")); // works
Run Code Online (Sandbox Code Playgroud)

所以对象的唯一副本是在赋值中

既然你的类无论如何都要存储一个副本,那么一个常见的模式(参见Modern Effective C++进行大讨论)就是坚持使用pass-by-value,并使用参数中的move-assignment:

void setA(QString val) {
    this->a = std::move(val);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以在setA使用临时/右值调用时保存副本(val然后将进行移动构造,并且您将再次移动,从而导致2次移动而不是1次复制+ 1次移动的const-reference方法) .如果setA使用左值调用,则需要支付1个副本+ 1个移动(而不是1个const-reference方法的副本).