1

可能重复:
在 C++ 中,从函数返回向量仍然是不好的做法吗?

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

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

而不是这种形式:

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

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

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


编辑

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

4

4 回答 4

7

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

没有

现代 C++ 编译器执行命名返回值优化 (NRVO),这实际上意味着编译器可靠地省略了此处的副本。不执行复制。

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

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

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

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

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

于 2013-01-22T18:20:46.323 回答
3

按值返回:

std::vector<int> func();

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

于 2013-01-22T18:20:29.673 回答
2

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

更重要的是,使用 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 的优点,因为并非所有目标编译器都支持它。

于 2013-01-22T18:50:39.560 回答
1
std::vector<int> func();

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

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

于 2013-01-22T18:20:39.910 回答