我想知道以下三种方法之间是否存在差异:
void FillVector_1(vector<int>& v) {
v.push_back(1); // lots of push_backs!
}
vector<int> FillVector_2() {
vector<int> v;
v.push_back(1); // lots of push_backs!
return v;
}
vector<int> FillVector_3() {
int tab[SZ] = { 1, 2, 3, /*...*/ };
return vector<int>(tab, tab + SZ);
}
答案 0 :(得分:16)
最大的区别在于第一种方式附加到现有内容,而另外两种方式填充空向量。 :)
我认为您要查找的关键字是return value optimization,这应该是相当常见的(使用G ++,您必须专门关闭它以防止它被应用)。也就是说,如果用法如下:
vector<int> vec = fill_vector();
然后可能很容易就没有副本(并且该功能更容易使用)。
如果您正在使用现有的载体
vector<int> vec;
while (something)
{
vec = fill_vector();
//do things
}
然后使用out参数将避免在循环中创建向量并复制数据。
答案 1 :(得分:9)
惯用的C ++方法是使用输出迭代器抽象容器类型:
template<typename OutputIterator>
void FillContainer(OutputIterator it) {
*it++ = 1;
...
}
然后它可以与vector一起使用:
std::vector<int> v;
FillContainer(std::back_inserter(v));
性能(以及其他优点,例如能够填充非空容器)与您的选项#1相同。另一个好处是,如果使用了适当类型的迭代器(例如ostream_iterator
),这可以用于以流模式输出,其中结果立即被处理并被丢弃而不被存储。
答案 2 :(得分:6)
人们会认为参数是最好的,但在实践中通常不是。这取决于编译器。一些编译器(我认为实际上是最新的编译器)将应用Return Value Optimization - Visual Studio 2005及更高版本应该在您提供的两种情况下都这样做(参见Named Return Value Optimization in Visual C++ 2005)。
确定最佳方法是检查生成的反汇编。
答案 3 :(得分:5)
在混音中添加第四个变体:
void FillVector_4(vector<int>& v) {
static const int tab[SZ] = {1,2,3, ... };
v.assign(tab,tab+SZ);
}
如果您正在考虑性能版本2和版本3 可能使编译器为返回值创建vector<int>
副本。也就是说,如果编译器不能做NRVO(命名返回值优化)。此外,没有push_back
的连续reserve
可能导致一些重新分配,因为向量需要增长。这是否重要取决于你试图解决的问题。
您会很高兴知道C ++ 0x将使返回本地创建的向量非常有效。我还建议阅读David Abrahams article series关于有效价值类型,包括传递/返回。
答案 4 :(得分:2)
第一个肯定不会复制矢量。
复制矢量的成本在矢量中的元素数量上可以是线性的。
第一个不会在任何平台或编译器上引入线性行为的风险,也不会产生分析和重构的成本。
答案 5 :(得分:0)
乍看之下,前两个可能会更多地调整矢量大小,而第三个可能不需要在矢量运行时调整大小。这可以通过在回击之前自己调整大小来缓解。