按值:

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时,实际上是在使用HugeObjectoperator=。这与构造不同。如果类未定义operator=,则C++实现对其进行合成;否则,C++实现将其合成。此默认设置通过将基本类型的右侧对象(例如double)的每个成员分配给左侧对象上的相应成员来实现。对于存储为hugeObject,变量的类类型,将调用其对应的operator=

现在要直接回答该问题,如果您想限制制作的副本,只需将h分配给hugeObject中的SetObject引用,因为这两个实例都已被实例化:
void SetObject(const HugeObject& hugeObject) {
    h = hugeObject;
}

尽管从技术上讲超出了范围,但const HugeObject&的值是通过HugeObjectoperator=复制到h的。这不会隐式构造一个新对象,因为两个对象都已被实例化。再次,它只是调用operator=

10-05 21:31