【问题标题】:C++ Always Const Reference in Constructor?C++ 总是在构造函数中引用常量?
【发布时间】:2015-12-17 06:31:42
【问题描述】:

所以考虑下面的代码:

#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 从构造函数复制到成员变量时。

我们知道我们不能低于 1 个副本(除非我们去 heap &amp; pointers)。那么我们为什么不总是写:

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

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

【问题讨论】:

  • we will garantie 1 less copy 这仅在副本昂贵时才重要。复制 int 很便宜 - 比通过引用访问同一 int 所需的间接成本更低。
  • 并且没有人阻止您改用const A&amp; data。对于 POD,它没有任何区别,可能编译器优化了间接并简单地复制了 int 等。
  • 因为您正在寻找的语义是移动语义(右值引用附带)而不是副本。
  • c++ 中的所有内容都是通过值“在引擎盖下”传递的,这是从 c 继承而来的。由于引用可以并且通常使用指针实现,因此您仍然必须为每个函数调用复制底层指针。这将比复制一个 int 更昂贵,因为你最终会得到一个间接的结果。
  • 我们总是将 const ref 用于非平凡的类型。除非我们使用 move 语义。不仅适用于构造函数。除非你特别想要一份副本。

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


【解决方案1】:

如果你移动你正在消费的对象,你实际上应该通过引用传递你的参数,可能是T const&amp;。如果你确实使用了你的论点,你应该通过值传递 move-aware 类型的对象(即定义移动构造函数的类型)并移动它。也就是说,如果A 是移动感知的,即有一个构造函数A::A(A&amp;&amp;),你会使用:

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

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

【讨论】:

    【解决方案2】:

    您的查询有矛盾。

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

    其次,通过值传递对象作为参考和基元是为了优化大小。

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

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

    所以如果你想将值存储在被调用函数的局部变量中,无论是通过值还是引用传递,都必须再次调用构造函数。

    【讨论】:

      【解决方案3】:

      原始类型在不需要时不会被复制。它们一直在堆栈或寄存器中直到结束。

      【讨论】:

        猜你喜欢
        • 2015-08-27
        • 1970-01-01
        • 2016-02-15
        • 2015-07-24
        • 2012-04-04
        • 2010-11-27
        • 2013-04-16
        • 2018-09-08
        • 1970-01-01
        相关资源
        最近更新 更多