返回语句与接受要写入的指针

Return statement vs. accepting pointer to write into

本文关键字:指针 语句 返回      更新时间:2023-10-16

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

在性能方面,当需要从函数返回"较重"的对象(如std::vectorstd::string)时,是否建议使用以下形式

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

而不是这种形式:

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

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

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


编辑

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

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

没有

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

请注意,无论您使用的是哪个C++版本,这都是如此:C++03 和 C++11 一样。C++11 中唯一改变的是,当无法执行复制省略时,该语言使库更容易有效地移出值(如此处发生)。

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

std::string foo() {
    std::string one = "Foo";
    std::string two = "Bar";
    if (rand() % 2 == 0)
        return one;
    else
        return two;
}

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

按值返回:

std::vector<int> func();

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

允许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的优势,因为并非所有目标编译器都支持它。

std::vector<int> func();

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

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