对于C++/C++ 11中的大数据,哪种"返回"方法更好?

Reg*_*gis 9 c++ return-value parameter-passing return-value-optimization c++11

这个问题是由C++ 11中关于RVO的混淆引发的.

我有两种方法来"返回"值:返回通过值通过引用参数返回.如果我考虑性能,我更喜欢第一个.由于按值返回更自然,我可以轻松区分输入和输出.但是,如果我在回归大数据时考虑效率.我无法决定,因为在C++ 11中,有RVO.

这是我的示例代码,这两个代码执行相同的工作:

按价值返回

struct SolutionType
{
    vector<double> X;
    vector<double> Y;
    SolutionType(int N) : X(N),Y(N) { }
};

SolutionType firstReturnMethod(const double input1,
                               const double input2);
{
    // Some work is here

    SolutionType tmp_solution(N); 
    // since the name is too long, I make alias.
    vector<double> &x = tmp_solution.X;
    vector<double> &y = tmp_solution.Y;

    for (...)
    {
    // some operation about x and y
    // after that these two vectors become very large
    }

    return tmp_solution;
}
Run Code Online (Sandbox Code Playgroud)

通过参考参数返回

void secondReturnMethod(SolutionType& solution,
                        const double input1,
                        const double input2);
{
    // Some work is here        

    // since the name is too long, I make alias.
    vector<double> &x = solution.X;
    vector<double> &y = solution.Y;

    for (...)
    {
    // some operation about x and y
    // after that these two vectors become very large
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

  1. 如何确保在C++ 11中发生RVO?
  2. 如果我们确定RVO已经发生,那么在现今的C++编程中,你推荐哪种"返回"方法?为什么?
  3. 为什么有些库使用返回引用参数,代码样式或历史原因?

更新 感谢这些答案,我知道第一种方法在大多数方面都更好.

这是一些有用的相关链接,可以帮助我理解这个问题:

  1. 如何在C++ 11中有效地返回大数据
  2. 在C++中,从函数返回向量仍然是不好的做法吗?
  3. 想要速度?通过价值.

Ser*_*eyA 16

首先,您所做的正确技术术语是NRVO.RVO与被退回的临时工具有关:

X foo() {
   return make_x();
}
Run Code Online (Sandbox Code Playgroud)

NRVO引用返回的命名对象:

X foo() {
    X x = make_x();
    x.do_stuff();
    return x;
}
Run Code Online (Sandbox Code Playgroud)

其次,(N)RVO是编译器优化,并非强制要求.但是,您可以非常肯定,如果使用现代编译器,(N)RVO将会非常积极地使用.

第三,(N)RVO 不是 C++ 11的功能 - 它早在2011年就已存在.

最重要的是,你在C++ 11中拥有的是一个移动构造函数.因此,如果您的类支持移动语义,即使(N)RVO没有发生,它也会被移动而不是被复制.不幸的是,并非一切都可以在语义上有效地移动.

第五,通过引用返回是一个可怕的反模式.它确保对象将被有效地创建两次 - 第一次作为"空"对象,第二次填充数据时 - 它使您无法使用"空"状态不是有效不变量的对象.

  • 不是*第四*的忠实粉丝,嗯? (7认同)
  • @Zereges永远不会返回使用`return std :: move(something);`这是一种悲观. (4认同)
  • @IInspectable,有人避免13,Japaneese不喜欢6(如果我没有在这里弄错),我可以成为那个不喜欢4的人吗?:))JK.感谢您发现它. (3认同)
  • @ tobi303,我想在第五个中说的是你首先将对象创建为一个空对象(构造),而不是用数据填充它 - 这也可以被认为是一个构造步骤(参见两步构造函数) ).这是低效的,但更糟糕的是,它要求你的类有一个默认的构造函数 - 这可能在语义上是不合适的. (2认同)