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 或指针传递,你可以这样做,但你是否从中得到了任何东西。

如果您想将被调用函数中的值复制到其他变量中,则将再次调用构造函数。

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