通过值或引用传递给需要存储副本的C++构造函数?

Kur*_*ter 5 c++ optimization constructor pass-by-reference pass-by-value

C++(隐式或显式)值构造函数是否应该通过value或reference-to-const接受其参数,当它需要以任何方式在其对象中存储参数的副本时?

这是我能想到的最短的例子:

struct foo {
    bar _b;
    foo(bar [const&] b) // pass by value or reference-to-const?
        : _b(b) { }
};
Run Code Online (Sandbox Code Playgroud)

这里的想法是,我希望在创建foo对象时,以创建foo对象的各种方式最小化对bar的复制构造函数的调用.

请注意我对copy elision和(Named)返回值优化有一点了解,我读过"想要速度?通过值传递",但我不认为这篇文章直接针对这个用例.

编辑:我应该更具体.

假设我无法知道sizeof(bar),或者是否bar是基本的内置类型(bar可能是模板参数,foo可能是类模板而不是类).另外,不要假设foo构造函数可以内联(或者bar就此而言).假设我至少可能使用实现RVO的编译器.

我想是为了有一个可能性(因为编译器优化),像这样的通话将调用没有调用bar"(S执行时甚至拷贝构造函数凡_b(b)foo的初始化列表)":

foo f = function_that_creates_and_returns_a_bar_object_using_rvo();
Run Code Online (Sandbox Code Playgroud)

是否有可能(鉴于C++ 98标准)可以这样做,如果是这样,如果foo通过引用而不是值接受其参数,它或多或少可能工作?

Dou*_* T. 5

在所有条件相同的情况下,我通过const传递足够复杂的类,并为POD和简单对象赋值.

规定优点/缺点是通过const引用而不是传统的值传递

正面:

  • 避免复制(对于带有昂贵副本的对象来说,大加一个)
  • 只读访问权限

劣势:

  • 如果他们真的想要,有人可以将const从参考文献中删除

更重要的是,积极的是你明确地控制复制何时发生(在你的情况下,在初始化列表中初始化_b时).思考负面因素......我同意这是一种风险.我想几乎所有优秀的程序员都会因为使用const_cast而感到肮脏.此外,你可以尽职尽责地搜索const_cast并将西红柿扔给那些从const中抛出const的人.但嘿,你永远不知道,谁有时间像鹰一样看代码:)?

我的主观意见是,在足够复杂的类和性能重要的环境中,避免复制构造函数的好处超过了风险.但是对于非常愚蠢和POD类,我倾向于复制数据并传递值.


小智 2

在C++98和C++03中,应该通过const& bar然后复制。在 C++0x 中,您应该传递bar然后执行移动(前提是bar有移动构造函数)。

#include <utility>

struct foo
{
    bar _b;

    foo(bar b) : _b(std::move(b)) {}
};
Run Code Online (Sandbox Code Playgroud)

如果使用左值参数构造 foo ,则将调用复制构造函数来创建副本b,并且该副本将被移动到_b。如果使用右值参数构造 foo,bar则将调用 的 move 构造函数将其移入b,然后再次将其移入_b