【问题标题】:Returning a c++ std::vector without a copy?返回没有副本的c ++ std::vector?
【发布时间】:2011-04-12 21:10:15
【问题描述】:

是否可以在不复制的情况下从函数返回标准容器?

示例代码:

std::vector<A> MyFunc();

...

std::vector<A> b = MyFunc();

据我了解,这会将返回值复制到一个新向量 b 中。使函数返回引用或类似的东西可以避免复制吗?

【问题讨论】:

标签: c++ stl copy return-value temporary


【解决方案1】:

如果您的编译器支持 NRVO,那么只要返回对象的函数满足某些条件,就不会进行复制。值得庆幸的是,这最终被添加到 Visual C++ 2005 (v8.0) 中,如果容器很大,这显然会对性能产生重大的 +ve 影响。

如果您自己的编译器文档没有说明它是否受支持,您应该能够将 C++ 代码编译为汇编器(在优化/发布模式下)并使用简单的示例函数检查所做的工作。

还有一个很棒的更广泛的讨论here

【讨论】:

  • 谢谢!对 gcc 中的 NRVO 有任何想法吗?
  • @static_rtti - 我将不得不听从 Linux 的人的意见,因为害怕把脚放在嘴里
  • AFAIK,对于 GCC,您必须使用 -fno-elide-constructors 关闭此优化,因为即使使用 -O0 也会启用它。
  • @static_rtti:GCC 非常擅长删除不必要的副本。据我所知,no 其他编译器在这方面更好——只是同样好或差。
  • 同意 peterchen 的观点,在您的链接文档中概述了许多 NRVO 不会启动的情况。我认为答案应该讨论 C++0x 移动语义,值得成为投票最多和选择的答案,所以不幸的是,我对此表示反对。编译器永远不需要执行任何优化 - 使用移动语义,您可以要求编译器不进行复制。
【解决方案2】:

绑定到const 引用的右值(“临时”)的生命周期将延长到引用生命周期的末尾。因此,如果您不需要修改该向量,则可以执行以下操作:

const std::vector<A>& b = MyFunc();

如果您需要修改向量,只需以最容易阅读的方式对其进行编码,直到您有证据(通过分析获得)该行甚至在性能方面也很重要。

否则依赖于 C++1x 及其右值引用和移动语义“现在很快就会出现”并优化该副本,而无需您做任何事情。

【讨论】:

    【解决方案3】:

    如果你可以修改函数的签名,那么你可以使用

    std::vector<A>& MyFunc(); 
    

    void MyFunc(std::vector<A>& vect);
    

    您也可以返回一个智能指针,但这涉及到新对象。

    some_smart_pointer<std::vector<A>> MyFunc();
    

    HTH

    【讨论】:

    • 如果您返回函数中的本地向量,第一个可能不起作用。第二个很好
    • +1 第二种形式是执行此操作的常用方法。第一个例子std::vector&lt;A&gt;&amp; MyFunc(); 的问题是向量必须被分配到某个地方——MyFunc 不能在堆栈上分配它并返回一个引用。如果向量是类成员并且您只是返回对现有向量的引用,这是可能的。
    • @John Burton/@beezler - 假设返回的容器在被调用函数中是基于堆栈的,“不工作”是温和的。
    • @John Burton/@Steve Townsend:为什么它不起作用?
    • @static_rtti:如果对象是在栈上分配的,当函数返回时,它会超出范围。所以你只剩下一个对不再存在的对象的引用。
    猜你喜欢
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多