按值:
class Test {
private:
HugeObject h; // Copy 1
public:
void SetObject(HugeObject hugeObject) { // Copy 2
h = hugeObject; // Copy 3
}
}
// Somewhere else
Test t();
t.SetObject(HugeObject());
这很不好,因为创建了三个隐式副本。如果我将
SetObject()
的参数更改为const HugeObject& hugeObject
,那也很糟糕,因为我将存储在该函数范围之外不再存在的内容。因此,为了防止复制两次并存储无效数据,我可以只复制两次:
void SetObject(const HugeObject& hugeObject) {
h = HugeObject(hugeObject); // Copy constructor
}
这是处理这种情况的有效方法,还是我误会了某些东西?愚蠢的优化还是根本没有优化?除了存储指针,还有更好的方法吗?
最佳答案
当您在类中首先声明h
时,实际上您正在执行的是调用对象的默认构造函数,该默认构造函数是在创建不使用显式语法的对象时隐式调用的。那是,
HugeObject h; // Calls default constructor implicitly.
HugeObject h2 = HugeObject(); // Still calls default constructor.
HugeObject ougeHobject = HugeObject(h); // Calls copy constructor.
h2 = ougeHobject; // calls HugeObject's operator=
最后一部分是我真正要了解的内容。当您将
h
分配给hugeObject
中的SetObject
时,实际上是在使用HugeObject
的operator=
。这与构造不同。如果类未定义operator=
,则C++实现对其进行合成;否则,C++实现将其合成。此默认设置通过将基本类型的右侧对象(例如double
)的每个成员分配给左侧对象上的相应成员来实现。对于存储为hugeObject,
变量的类类型,将调用其对应的operator=
。现在要直接回答该问题,如果您想限制制作的副本,只需将h分配给
hugeObject
中的SetObject
引用,因为这两个实例都已被实例化:void SetObject(const HugeObject& hugeObject) {
h = hugeObject;
}
尽管从技术上讲超出了范围,但
const HugeObject&
的值是通过HugeObject
的operator=
复制到h
的。这不会隐式构造一个新对象,因为两个对象都已被实例化。再次,它只是调用operator=
。