【问题标题】:Return statement vs. accepting pointer to write into [duplicate]返回语句与接受指针写入[重复]
【发布时间】:2013-01-22 18:19:17
【问题描述】:

可能重复:
In C++, is it still bad practice to return a vector from a function?

在性能方面,当需要从函数中返回std::vectorstd::string等“较重”的对象时,建议使用这种形式

void func(std::vector<int> *dest)
{
}

而不是这种形式:

std::vector<int> func()
{
    std::vector<int> arr;
    // ...
    return arr;
}

我假设第一种形式应该更快,但同时我经常看到第二种形式,例如 Qt API 经常返回 QString,可能是因为它更方便或更直观使用。

我还想知道是否有编译器优化可以在使用 return 语句时消除不必要的对象复制。


编辑

是否有今天仍在使用的任何流行的编译器不执行答案中提到的优化?

【问题讨论】:

标签: c++ function return


【解决方案1】:

是否推荐使用[按指针传递]而不是[按值返回]?

A modern C++ compiler performs named return value optimisation (NRVO) 这实际上意味着编译器可靠地省略了此处的副本。不执行复制。

请注意,这与您使用的 C++ 版本无关:C++03 和 C++11 一样。在 C++11 中唯一改变的是该语言使库更容易在无法执行复制省略时高效地移出一个值(就像这里发生的那样)。。 p>

对于返回值,通常可以执行复制省略 - 在其他情况下(例如按值传递参数)更相关。不过也有例外;以下代码不能使用命名返回值优化。它可以使用 C++11 移动:

std::string foo() {
    std::string one = "Foo";
    std::string two = "Bar";

    if (rand() % 2 == 0)
        return one;
    else
        return two;
}

原因是现在两个代码路径返回不同的命名对象;这可以防止 NRVO。

【讨论】:

  • 由于其他答案提到了 C++11,这在它之前是否成立?意思是,最早支持的C++版本是哪个?
  • @satuon 它以前肯定成立,是的。但是,请参阅我的回答中的警告。
  • @KonradRudolph:但是您的示例可以使用(未命名的)RVO。您需要一个示例返回两个不同的名为 std::string 的变量来破坏优化。
  • @Mike 查看更新的示例,我也注意到了。嗯,你说得很好,让我想一个更好的例子,它不能被编译器轻易重写(if 分支中的局部变量也不会直接剪切它)。
  • @KonradRudolph 太好了,直到现在我都在使用指针,这让代码看起来很丑,很高兴知道我可以只返回数组。
【解决方案2】:

按值返回:

std::vector<int> func();

C++ 允许在这种情况下进行复制省略,除此之外,新的 C++ 定义了 移动语义 以使这些操作变得便宜。编译器通常可以很好地实现这一点。 (使用复制省略,您的本地 arr 实际上最终会在接收者调用站点变量中构建。这种情况也称为“返回值优化”。)

【讨论】:

    【解决方案3】:

    ARM (1990) 中存在允许 RVO 和 NRVO 的规则, 所以如果任何编译器没有实现它们,那将是令人惊讶的。

    更重要的是,使用 out 参数(指针或 对非常量的引用)非常笨拙。不要这样做, 直到分析器说你真的有时间问题 因为复制了返回值。此时, 重载函数,大致如下:

    void func( std::vector<int>& dest )
    {
        //  ...
    }
    
    std::vector<int> func()
    {
        std::vector<int> results;
        func( results );
        return results;
    }
    

    然后在探查器显示您所在的位置尝试两者 遇到问题,然后选择解决问题的那个(如果 它有所作为)。

    我实际上不得不这样做一次,但那是在某个时候 1991 或 1992 几年来,我一直在做一些漂亮的表演 关键的东西;我们仍然定期返回std::vector 或我们的 在内部Matrix 课程中。没有C++11的优势, 因为并非所有目标编译器都支持它。

    【讨论】:

      【解决方案4】:
      std::vector<int> func();
      

      对于 C++11,以上应该是你的函数。当函数返回时,本地std::vector 对象将被移动。如果可能,编译器甚至可以省略 move

      简而言之,不用担心。按值返回。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-22
        • 2013-01-08
        • 2012-08-01
        • 2012-08-22
        • 1970-01-01
        相关资源
        最近更新 更多