现在,我知道这是一个常见问题,但我还没能真正找到答案。这真的是一个关于标准的问题。我正在研究一个涉及遗传算法的项目。但是,当涉及到返回矢量时,我遇到了瓶颈。是否有适当的"这样做的方式。通常我使用动态分配的数组,并返回一个指向新创建的数组的指针。
obj* func(obj* foo);
这样,一切都很有效,并且没有数据复制。有没有相当于用矢量这样做?这个向量中有对象,所以按值返回它会很慢。是通过"结果"的唯一解决方案。矢量参考?
void func(vector<obj> &input, vector<obj> &result);
并且,在备注以供将来参考时,在动态分配的数组上使用向量或其他STL容器是标准做法吗?动态分配的数组是否仅用作设计容器的低级工具?它们只是过去的遗物吗?
答案 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);