C ++始终是构造函数中的Const引用?

时间:2015-09-20 14:09:03

标签: c++ c++11 constructor pass-by-reference pass-by-value

请考虑以下代码:

#include <iostream>
using namespace std;

class A {
public:
    A() = default;

    A(const A& rhs) {
        cout << "Copy was made!" << endl;
    }
};

class B {
public:
    A data;
    int foo;

    B(A data, int foo) : data(data), foo(foo) {
    }
};

int main() {
    A data;

    B foo(data, 10);

    return 0;
}

打印出来:

  

复制了!

     

复制了!

是的,没错,它会复制两次!

当我们将data传递给B's构造函数时,第一个副本就会发生。 当我们将data从构造函数复制到memeber变量时,第二个副本就会发生。

我们知道我们不能复制1份(除非我们去heap & pointers)。那么为什么我们不总是写:

B (const A& data, const int& foo, const SomeOtherType& bar, const float& aFloatyNumber) ......等等。

我知道通过值传递int,float等是很便宜的。但是,通过始终将const ref作为Constructor参数,我们将保证减少1份副本。

3 个答案:

答案 0 :(得分:5)

如果您移动您正在消费的对象,实际上通过引用传递您的参数,可能是T const&。如果你确实使用了你的参数,你应该通过值传递移动感知类型的对象(即,定义移动构造函数的类型),然后移动它。也就是说,如果A具有移动感知功能,即具有构造函数A::A(A&&),则可以使用:

B(A data, int foo) : data(std::move(data)), foo(foo) {
}

如果您的类型不支持移动,或者您不需要从构造中挤出最后一点性能,或者类型是仅移动的,则可以安全地通过T const&传递对象。

答案 1 :(得分:1)

您的查询有矛盾。

在第一种情况下,当您通过值传递时,您正在使用第一个使用其他对象,这就是需要再次调用构造函数的原因。

其次,按值将对象作为引用和基元传递是为了进行大小优化。

如果你想将int作为const ref或指针传递,那么你可以做到但是你从中得到了什么。

如果要在某个其他变量中将该值复制到被调用函数中,则将再次调用构造函数。

因此,如果要将值存储在被调用函数的局部变量中,则无论是否通过值或引用传递,都必须再次调用构造函数。

答案 2 :(得分:0)

原始类型在不需要时不会被复制。他们留在堆栈或寄存器中直到最后。