C++ 总是在构造函数中使用 Const 引用?
C++ Always Const Reference in Constructor?
因此请考虑以下代码:
#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;
}
打印出来:
Copy was made!
Copy was made!
没错,它复制了两次!
第一个副本发生在我们将 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 个副本。
原始类型在不需要时不会被复制。他们一直留在堆栈或寄存器中,直到结束。
如果你不移动你正在消耗的对象,你实际上应该通过引用传递你的参数,可能作为T const&
.如果你确实使用了你的参数,你应该通过值 和 传递 move-aware 类型的对象(即定义移动构造函数的类型)它。也就是说,如果 A
是移动感知的,即具有构造函数 A::A(A&&)
,您将使用:
B(A data, int foo) : data(std::move(data)), foo(foo) {
}
如果您的类型不是移动感知的,或者您不需要从构造中挤出最后一点性能,或者类型是仅移动的,您可以通过 T const&
安全地传递对象。
您的查询自相矛盾。
在第一种情况下,当您按值传递时,您正在使用第一个对象创建其他对象,这就是为什么需要再次调用构造函数的原因。
其次,通过值传递对象作为参考和原语以优化大小。
如果你想将 int 作为 const ref 或指针传递,你可以这样做,但你是否从中得到了任何东西。
如果您想将被调用函数中的值复制到其他变量中,则将再次调用构造函数。
因此,如果要将值存储在被调用函数的局部变量中,无论是值传递还是引用传递,都必须再次调用构造函数。
因此请考虑以下代码:
#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;
}
打印出来:
Copy was made!
Copy was made!
没错,它复制了两次!
第一个副本发生在我们将 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 个副本。
原始类型在不需要时不会被复制。他们一直留在堆栈或寄存器中,直到结束。
如果你不移动你正在消耗的对象,你实际上应该通过引用传递你的参数,可能作为T const&
.如果你确实使用了你的参数,你应该通过值 和 传递 move-aware 类型的对象(即定义移动构造函数的类型)它。也就是说,如果 A
是移动感知的,即具有构造函数 A::A(A&&)
,您将使用:
B(A data, int foo) : data(std::move(data)), foo(foo) {
}
如果您的类型不是移动感知的,或者您不需要从构造中挤出最后一点性能,或者类型是仅移动的,您可以通过 T const&
安全地传递对象。
您的查询自相矛盾。
在第一种情况下,当您按值传递时,您正在使用第一个对象创建其他对象,这就是为什么需要再次调用构造函数的原因。
其次,通过值传递对象作为参考和原语以优化大小。
如果你想将 int 作为 const ref 或指针传递,你可以这样做,但你是否从中得到了任何东西。
如果您想将被调用函数中的值复制到其他变量中,则将再次调用构造函数。
因此,如果要将值存储在被调用函数的局部变量中,无论是值传递还是引用传递,都必须再次调用构造函数。