请考虑以下代码:
#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份副本。
答案 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)
原始类型在不需要时不会被复制。他们留在堆栈或寄存器中直到最后。