在C ++中返回Vectors标准

时间:2014-04-17 21:48:21

标签: c++ vector reference dynamic-arrays return-by-value

现在,我知道这是一个常见问题,但我还没能真正找到答案。这真的是一个关于标准的问题。我正在研究一个涉及遗传算法的项目。但是,当涉及到返回矢量时,我遇到了瓶颈。是否有适当的"这样做的方式。通常我使用动态分配的数组,并返回一个指向新创建的数组的指针。

obj* func(obj* foo);

这样,一切都很有效,并且没有数据复制。有没有相当于用矢量这样做?这个向量中有对象,所以按值返回它会很慢。是通过"结果"的唯一解决方案。矢量参考?

void func(vector<obj> &input, vector<obj> &result);

并且,在备注以供将来参考时,在动态分配的数组上使用向量或其他STL容器是标准做法吗?动态分配的数组是否仅用作设计容器的低级工具?它们只是过去的遗物吗?

4 个答案:

答案 0 :(得分:6)

vector<obj> func(const vector<obj>& input);

所有编译器默认情况下或在您启用优化时都会实施RVO,如果您不进行优化,则不必关心性能,因此无论如何都不会成为问题。

如果您的编译器符合C ++ 11标准,那么在最坏的情况下,不是复制1指针,当移动语义启动时,您将支付3个指针,这与分配内存的成本相比实际上没有成本。 / p>

构建一个简单的有意义的界面,然后衡量性能和瓶颈,并从那里进行优化。

根据您的使用模式,如果您可以重复使用输出容器,您可能希望将上述内容转换为:

void func(vector<obj>& output, const vector<obj>& input);

在创建新向量时,这将具有相同的性能,但如果您在循环中调用此函数,则可以避免一些分配:

std::vector<obj> output;
for ( ... ) {
   output.clear();
   func(output, input);

// compare with
for ( ... ) {
   std::vector<obj> output = func(input);

在第一个代码块中,如果所有向量的大小相同,clear()将删除元素,但保留缓冲区不变,以便下次调用func时不需要分配。在第二种情况下,它需要在func内部进行分配,并在范围的末尾解除分配。

这是一个稍微丑陋的使用界面,所以我会选择第一个(语义上更干净),并且仅在第一个证明出现多个分配问题时才使用第二个

答案 1 :(得分:2)

  

唯一的解决方案是通过&#34;结果&#34;矢量参考?

没有。您也可以传递一个迭代器,就像算法一样:

void func( InputIt first, InputIt last, OutputIt res);

然后您可以将其设为模板:

template< class InputIt, class OutputIt >
void func( InputIt first, InputIt last, OutputIt res);

答案 2 :(得分:2)

如果你想合理地确定你的函数没有复制向量,那么:

 void func(const vector<obj> &input, vector<obj> &result);

如果依靠编译器“返回值优化”(RTVO)就可以了(大多数优秀的编译器都这样做):

 vector<obj> func(const vector<obj> &input); 

返回值优化本质上是编译器知道我们正在返回向量副本的地方,因此它删除了返回内容时通常需要的“额外副本”,在本例中为{{1}来自vector<obj>。符合C ++ 11的编译器应该使用“移动构造函数”,如果它不能进行RTVO,这在整个方案中也是一个小成本。

如果您乐意动态分配矢量本身,可以返回指向它的指针,但这是一个很差的解决方案:

func

此解决方案依赖于分配vector<obj>* func(const vector<obj> &input); ,这意味着某处必须vector<obj>调用delete的结果。如果多次调用func,这样的代码的维护变得相当令人讨厌(特别是如果多次调用func,这在遗传分析情况下可能就是这种情况)。

通常很难获得引用的返回,所以如果你这样做,你可能做错了 - 不要这样做(除非你知道你在做什么以及为什么):

func

当然,它真的取决于你在向量上做了什么,如果你给出一个更具体的例子来说明你在函数内做了什么,可能还有其他更好的解决方案。

顺便说一下:

vector<obj>& func(const vector<obj> &input); 

是一个维护噩梦,因为如果在obj *func(obj *input) 中分配了obj*,那么调用者现在可以维护此结构。

最后,总是在处理性能时,在您的机器上使用您的编译器进行基准测试非常重要。不同的编译器和不同的系统表现不同 - 基于查看源代码进行猜测是一种非常糟糕的解决方案,用于理解将生成哪些代码以及它的速度。

答案 3 :(得分:0)

如果可以,请始终使用引用(&amp;)而不是使用类本身。这甚至引用了智能指针(std :: shared_ptr),因为即使是指针本身也会避免额外的复制。并且只是为了确保你的返回指针不会被覆盖,将const挂起到它,所以:

void Function(const std::shared_ptr<SomeClass> &someObject);