这是复制值两次吗?
Is this copying values twice?
假设我有一个像这样的 class:
class Foo
{
public:
QString a;
void setA(QString val);
}
并像这样实施 setA()
:
void Foo::setA(QString val)
{
this->a = val;
}
并像这样使用它:
Foo f;
QString v = "foo";
f.setA(v);
我是否在堆栈上复制了 v
结构两次?一个用于传递参数,另一个用于函数内的赋值,对吗?而使用 void setA(QString &val);
将避免复制对象两次,因为在第一个中我只是复制一个引用(指针)而不是整个对象,所以对象的唯一副本在赋值中:
this->a = val;
由于您使用的是 QString
,因此您不会有 2 个副本。复制构造函数有:
This operation takes constant time, because QString is implicitly shared. This makes returning a QString from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and that takes linear time.
所以在这种情况下,只有当您将 val
分配给 this->a
时,您才有一个副本
Am I copying the v struct twice on stack? one for pass in the argument and other in the assignment within the function, is this right?
没错。您正在按值传递,因此必须构造一个新对象(在您的情况下,通过复制构造函数)。
现在,在 QString
(以及 Qt 中的许多其他值类型)的特定情况下,该操作非常便宜,因为 QString 是 implicitly shared(读取:引用计数,写入时复制).对于其他数据类型,操作可能会很昂贵。
by rather using 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
so the only copy of the object is in the assignment
既然你的 class 存储了一份副本,那么一个常见的模式(参见 Modern Effective C++ 的一个大讨论)是坚持按值传递,并使用来自参数:
void setA(QString val) {
this->a = std::move(val);
}
在这种情况下,您可以保存一个副本,以防使用临时/右值调用 setA
(然后 val
将被移动构建,您将再次移动,从而导致 2移动而不是 1 个副本 + 1 个常量引用方法的移动)。在使用左值调用 setA
的情况下,您支付 1 个副本 + 1 个移动(而不是 1 个常量引用方法的副本)。
假设我有一个像这样的 class:
class Foo
{
public:
QString a;
void setA(QString val);
}
并像这样实施 setA()
:
void Foo::setA(QString val)
{
this->a = val;
}
并像这样使用它:
Foo f;
QString v = "foo";
f.setA(v);
我是否在堆栈上复制了 v
结构两次?一个用于传递参数,另一个用于函数内的赋值,对吗?而使用 void setA(QString &val);
将避免复制对象两次,因为在第一个中我只是复制一个引用(指针)而不是整个对象,所以对象的唯一副本在赋值中:
this->a = val;
由于您使用的是 QString
,因此您不会有 2 个副本。复制构造函数有:
This operation takes constant time, because QString is implicitly shared. This makes returning a QString from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and that takes linear time.
所以在这种情况下,只有当您将 val
分配给 this->a
Am I copying the v struct twice on stack? one for pass in the argument and other in the assignment within the function, is this right?
没错。您正在按值传递,因此必须构造一个新对象(在您的情况下,通过复制构造函数)。
现在,在 QString
(以及 Qt 中的许多其他值类型)的特定情况下,该操作非常便宜,因为 QString 是 implicitly shared(读取:引用计数,写入时复制).对于其他数据类型,操作可能会很昂贵。
by rather using 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
so the only copy of the object is in the assignment
既然你的 class 存储了一份副本,那么一个常见的模式(参见 Modern Effective C++ 的一个大讨论)是坚持按值传递,并使用来自参数:
void setA(QString val) {
this->a = std::move(val);
}
在这种情况下,您可以保存一个副本,以防使用临时/右值调用 setA
(然后 val
将被移动构建,您将再次移动,从而导致 2移动而不是 1 个副本 + 1 个常量引用方法的移动)。在使用左值调用 setA
的情况下,您支付 1 个副本 + 1 个移动(而不是 1 个常量引用方法的副本)。