返回向量vs使用向量的参数返回它

时间:2011-08-23 14:53:27

标签: c++ vector return

使用下面的代码,问题是:

如果使用“returnIntVector()”函数,向量是否从本地复制到“外部”(全局)范围?换句话说,与“getIntVector()” - 函数相比,它是更多的时间和内存消耗变化? (但提供相同的功能。)

#include <iostream>
#include <vector>
using namespace std;

vector<int> returnIntVector()
{
   vector<int> vecInts(10);
   for(unsigned int ui = 0; ui < vecInts.size(); ui++)
      vecInts[ui] = ui;

   return vecInts;
}

void getIntVector(vector<int> &vecInts)
{
   for(unsigned int ui = 0; ui < vecInts.size(); ui++)
      vecInts[ui] = ui;
}

int main()
{
   vector<int> vecInts = returnIntVector();
   for(unsigned int ui = 0; ui < vecInts.size(); ui++)
      cout << vecInts[ui] << endl;
   cout << endl;

   vector<int> vecInts2(10);
   getIntVector(vecInts2);
   for(unsigned int ui = 0; ui < vecInts2.size(); ui++)
      cout << vecInts2[ui] << endl;

   return 0;
}

6 个答案:

答案 0 :(得分:18)

理论上,是的,它被复制了。实际上,不,大多数现代编译器都利用return value optimization

因此,您可以编写语义正确的代码。如果您想要一个修改或检查值的函数,可以通过引用将其引入。您的代码不会这样做,它会创建一个不依赖于其他任何内容的新值,因此按值返回。

答案 1 :(得分:9)

使用第一种形式:返回向量的形式。一个好的编译器很可能会优化它。优化通常称为Return value optimization,简称RVO。

答案 2 :(得分:4)

其他人已经指出,通过一个体面的(不是很好的,仅仅是体面的)编译器,两者通常最终会生成相同的代码,因此两者的性能相同。

我认为值得一提的是其他一两点。首先,返回对象会正式复制对象;即使编译器优化代码以便永远不会发生复制,如果无法访问该类的复制文件,它仍然不会(或至少不应该)工作。 std::vector当然支持复制,完全有可能创建一个您可以像getIntVector一样修改的类,但不能像returnIntVector那样返回

其次,更重要的是,我通常建议不要使用 这些。您应该使用迭代器(或两个)来代替传递或返回(引用)向量。在这种情况下,您有几个完全合理的选择 - 您可以使用特殊迭代器,或创建一个小算法。迭代器版本看起来像这样:

#ifndef GEN_SEQ_INCLUDED_
#define GEN_SEQ_INCLUDED_

#include <iterator>

template <class T>
class sequence : public std::iterator<std::forward_iterator_tag, T>
{ 
    T val;
public:
    sequence(T init) : val(init) {}
    T operator *() { return val; }
    sequence &operator++() { ++val; return *this; }
    bool operator!=(sequence const &other) { return val != other.val; }
};

template <class T>
sequence<T> gen_seq(T const &val) {
    return sequence<T>(val);
}

#endif

您可以使用以下内容:

#include "gen_seq"

std::vector<int> vecInts(gen_seq(0), gen_seq(10));

虽然这种(有点)滥用迭代器的概念的论点是开放的,但我仍然认为它在实际的基础上更好 - 它允许你创建一个初始化的向量而不是创建一个空向量然后再填充它

算法替代方案如下所示:

template <class T, class OutIt>
class fill_seq_n(OutIt result, T num, T start = 0) {
    for (T i = start; i != num-start; ++i) {
        *result = i;
        ++result;
    }
}

......你会用这样的东西:

std::vector<int> vecInts;
fill_seq_n(std::back_inserter(vecInts), 10);

你也可以使用std::generate_n的函数对象,但至少IMO,这通常会比它的价值更麻烦。

只要我们谈论类似的事情,我也会替换它:

for(unsigned int ui = 0; ui < vecInts2.size(); ui++)
    cout << vecInts2[ui] << endl;

......有这样的事情:

std::copy(vecInts2.begin(), vecInts2.end(), 
          std::ostream_iterator<int>(std::cout, "\n"));

答案 3 :(得分:0)

理论上,returnIntVector函数按值返回向量,因此将创建一个副本,它将比仅填充现有向量的函数更耗时。更多内存也将用于存储副本,但只能暂时存储;由于vecInts是本地作用域的,因此它将被堆栈分配,并在returnIntVector返回后立即释放。然而,正如其他人所指出的那样,现代编译器将优化这些低效率。

答案 4 :(得分:0)

在C ++ 03天,大多数情况下建议使用getIntVector()。在returnIntVector()的情况下,它可能会创建一些不必要的临时值。

但是使用return value optimizationswaptimization,大多数都可以避免。在C ++ 11时代,由于移动语义,后者可能是有意义的。

答案 5 :(得分:-1)

returnIntVector 更耗时,因为它会返回向量的副本,除非使用单个指针实现向量实现,在这种情况下性能是相同的。

一般来说,您不应该依赖于实施,而是使用 getIntVector