函数返回C ++中的对象集合

时间:2013-02-21 14:05:46

标签: c++ design-patterns

在我目前的项目中,我需要实现一些功能/方法,这些功能/方法需要一些参数并生成一组结果(相当大)。因此,为了在不复制的情况下返回此集合,我可以创建一个新集合并返回一个智能指针:

boost::shared_ptr<std::vector<Stuff> > generate();

或参考将填充的载体:

void generate(std::vector<Stuff> &output);

这两种方法都有好处。第一个清楚地表明向量是函数的输出,在并行场景中使用它是微不足道的。第二个可能在循环中调用时更有效(因为我们不是每次都分配内存),但是那么参数是输出并不明显,有人需要从矢量中清除旧数据......

在现实生活中哪些更习惯(即什么是最佳做法)?在C#/ java中我会争论第一个,C ++中的情况是什么?

此外,是否可以使用C ++ 11有效地按值返回向量?会有什么陷阱?

5 个答案:

答案 0 :(得分:4)

首先做正确性,然后根据需要进行优化

同时使用移动语义和返回值优化共谋使普通函数结果不复制,您可能必须使用它来使其效率低,值得进行优化工作

所以,只需将集合作为函数结果返回,然后 MEASURE ,如果您觉得它太慢

答案 1 :(得分:2)

您应该按值返回。

  

是否可以使用C ++ 11有效地按值返回向量?

是的,C ++ 11支持move semantics。您返回一个值,但编译器知道它是临时的,因此可以调用一个特殊的构造函数(移动构造函数),该构造函数专门用于简单地“窃取返回对象的内容”。毕竟,你不再使用那个临时对象了,那么为什么要在你移动它的内容时复制呢?

除此之外,值得一提的是,大多数C ++编译器,甚至是C ++之前的版本11,都会实现(Named) Return Value Optimization,无论如何都会删除副本,不会产生任何开销。因此,您可能希望实际测量在优化之前(可能)获得的性能损失。

我认为只有在需要reference semantics时才应通过引用传递或返回共享指针。这似乎不是你的情况。

答案 2 :(得分:1)

还有另一种方法。如果你可以创建函数模板,那么让它们将输出迭代器(其类型是模板参数)作为参数:

tempalte<class OutputIterator>
void your_algorithm(OutputIterator out) {
    for(/*condition*/) {
        ++out = /* calculation */;
    }
}

这样做的好处是调用者可以决定他想要存储结果的集合类型(输出迭代器可以直接写入文件,或将结果存储在std::vector中,或过滤器它等。)。

答案 3 :(得分:1)

最佳做法可能会让您感到惊讶。我建议在C ++ 03和C ++ 11中按值返回。

  • 在C ++ 03中,如果您为std::vector创建generate本地并返回它,则编译器可能会删除该副本(几乎可以肯定)。见C ++03§12.8/ 15:

      

    在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象的名称时,可以通过构造省略复制操作自动对象直接进入函数的返回值

  • 在C ++ 11中,如果您创建一个std::vector本地generate并将其返回,则该副本将首先被视为移动(已经非常快)然后 可以被删除(几乎可以肯定)。见C ++11§12.8/ 31:

      

    在具有类返回类型的函数的return语句中,当表达式是非易失性自动对象(函数或catch子句参数除外)的名称时,具有与函数相同的cv-unqualified类型返回类型,通过将自动对象直接构造到函数的返回值

    中,可以省略复制/移动操作

    §12.8/ 32:

      

    当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就像对象是由右值指定一样。

所以按价值回归!

答案 4 :(得分:1)

信不信由你,我建议不要采取任何一种方法,只需采取明显的实施方式并按价值回报!编译器通常能够优化掉所引发的名义副本,将其完全删除。通过以最明显的方式编写代码,您可以非常清楚未来的维护者意图是什么。

但是,假设您尝试按值返回,并且您的程序运行速度太慢让我们进一步假设您的探查器显示按值返回实际上是您的瓶颈。在这种情况下,我将在堆上分配容器,并在C ++ 03中以auto_ptr或在C ++ 11中以unique_ptr形式返回,以清楚地表明正在转移所有权并且生成不是shared_ptr的副本。

最后,http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/处的系列文章提供了几乎完全相同问题的绝佳视角。