存储const引用参数中的成员变量

时间:2015-07-22 00:08:46

标签: c++ reference parameter-passing const pass-by-reference

按价值:

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
}

这是处理这种情况的有效方法还是我误解了什么?愚蠢的优化还是不优化?除了存储指针外还有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

  

这很糟糕,因为会创建三个隐式副本。

实际上,在这种情况下只会发生一个副本。 HugeObject()临时值作为参数hugeObject就地构建,然后从那里复制到h

  

如果我将SetObject()的参数更改为const HugeObject& hugeObject,那么它也很糟糕,因为我会存储在该函数范围之外不再存在的内容。< / p>

这也不准确 - 你还在复制到h,你没有存储对它的引用。在以下情况下,这样可以保存一份副本:

HugeObject h;
t.SetObject(h); // copy from h into t.h, no copy necessary
                // into the argument of SetObject()

hugeObjectconst&是在C ++ 03中完成此操作的最佳方法。如果您可以访问C ++ 11编译器,并且HugeObject可以有效地移动,那么您还应该添加rvalue重载:

void setObject(HugeObject&& hugeObject) {
    h = std::move(hugeObject);
}

答案 1 :(得分:1)

为什么不在施工期间拿到物体?然后你得到原创作品和副本。

#include <iostream>

using std::cout;

class Huge 
{
public:
    Huge() { cout << "constructor\n"; }
    Huge(const Huge & h) { cout << "copy\n"; }
    Huge & operator = (const Huge & h) { cout << "assignment\n"; return *this; }
};

class Holder
{
    Huge h;
public:
    Holder(const Huge & h_) : h(h_) {};
};

int main()
{
    Huge bar;
    Holder foo(bar);
}

输出:

constructor
copy

Live Example

答案 2 :(得分:1)

当您在课程中首先声明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&#39; s operator=。这与构造相同。如果operator=不是由类定义的,那么C ++实现会合成它;此默认值的工作原理是将基本类型(例如double)的右侧对象的每个成员分配给左侧对象上的相应成员。对于存储为hugeObject,变量的类类型,将调用其对应的operator=

要立即直接回答此问题,如果您要限制所制作的副本,只需将h分配给hugeObject中的SetObject引用,因为两者都已实例化:

void SetObject(const HugeObject& hugeObject) {
    h = hugeObject;
}

虽然技术上超出了范围,但const HugeObject&的值会通过HugeObject&n; operator=复制到h。这不会隐式构造一个新对象,因为它们都已经实例化了;再次,它只是调用operator=