对于一个非常简单的事情,例如在向量中打印每个元素,在C ++中使用哪种更好的方法?
我一直在用这个:
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
之前,但是在我看过的Boost :: filesystem示例之一:
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
对我而言,它看起来更复杂,我不明白为什么它比我一直使用的更好。
你能告诉我为什么这个版本会更好吗?或者对于打印矢量元素之类的简单事情无关紧要?
i != values.end()
使迭代变慢吗?
或者是const_iterator
vs iterator
? const_iterator在这样的循环中更快吗?
答案 0 :(得分:10)
Foo x = y;
和Foo x(y);
相同,因此请根据您的喜好使用。
将end
挂出循环可能也可能不是编译器会做的事情,无论如何,它明确表示容器端没有改变。
如果您不打算修改元素,请使用const-iterators,因为这就是它们的含义。
for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
/* ... */
}
在C ++ 0x中,使用auto
+ cbegin()
:
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
(也许您想使用现成的container pretty-printer?)
答案 1 :(得分:6)
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
... ... VS
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
对我来说[后者,在增强中看到]看起来更复杂,我不明白为什么它比我一直使用的更好。
我会说,对于任何没有特定理由喜欢后者的人来说,它会更加复杂,从而扭曲了感知。但让我们继续讨论为什么它会更好......
你能告诉我为什么这个版本更好?或者对于像矢量打印元素这样的简单事情无关紧要? i!= values.end()会使迭代变慢吗?
it_end
效果:it_end
只获取end()
值作为循环的开始。对于任何计算end()
都非常昂贵的容器,只调用一次就可以节省CPU时间。对于任何中途不错的真实C ++标准库,所有end()
函数都不执行任何计算,并且可以内联以获得相同的性能。在实践中,除非有可能需要放入一个非标准的容器,这个容器的end()
函数更加昂贵,所以在优化代码中明确“缓存”end()
没有任何好处。
这很有意思,因为vector
表示size()
可能需要一个小的计算 - 概念上从begin()
减去end()
然后除以sizeof(value_type)
(编译器在指针运算期间隐式地按大小缩放),例如GCC 4.5.2:
size_type size() const
{ return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
维护:如果代码演变为插入或擦除循环内的元素(显然是迭代器本身没有失效的方式 - 对于地图/集合/列表等是合理的如果还需要明确重新计算缓存的end()
值,那么这又是一个维护点(因此也就是错误倾向)。
一个小细节,但这里vec
必须是typedef
,而恕我直言通常最好对容器使用typedef,因为它放松了容器类型的耦合,并且可以访问迭代器类型
type identifier(expr)
风格和纪录片重点:type identifier(expr)
比type identifier = expr
更直接地表示构造函数调用,这是某些人更喜欢该形式的主要原因。我通常更喜欢后者,因为我喜欢强调赋值的 sense ...它在视觉上是明确的,而函数调用符号用于很多事情。
近等效:对于大多数类,无论如何都调用相同的构造函数,但是如果type
具有expr
类型的显式构造函数{1}},如果使用=
,它将被传递。更糟糕的是,一些其他转换可能允许使用不太理想的构造函数。例如,X x = 3.14;
会传递explicit X::X(double);
以匹配X::X(int)
- 您可能会得到一个不那么精确(或者只是完全错误)的结果 - 但我还是会被这样的问题所以它非常理论化!
或者是const_iterator与迭代器? const_iterator在这样的循环中更快吗?
对于标准容器,const_iterator
和iterator
执行相同,但后者意味着您希望能够在迭代时修改元素。使用您不打算这样做的const_iterator
文档,编译器将捕获尝试修改的迭代器的任何矛盾用法。例如,当您打算增加迭代器本身时,您将无法意外地增加迭代器地址的值。
鉴于C ++ 0x在其他答案中已被提及 - 但只有auto
和cbegin
/ cend
的增量收益 - 还支持新的表示法:
for (const Foo& foo: container)
// use foo...
答案 2 :(得分:3)
要在矢量中打印项目,您不应使用上述任何一项(至少是IMO)。
我建议这样的事情:
std::copy(values.begin(), values.end(),
std::ostream_iterator<T>(std::cout, "\n"));
答案 3 :(得分:0)
您只能通过索引
访问它们int main(int argc, char* argv[])
{
std::vector<int> test;
test.push_back(10);
test.push_back(11);
test.push_back(12);
for(int i = 0; i < test.size(); i++)
printf("%d\n", test[i]);
}
打印出来: 10 11 12
答案 4 :(得分:0)
我认为这不重要。在内部,它们做同样的事情,所以编译器应该优化它。我会亲自使用第一个版本,因为它更加清晰,因为它紧跟着for循环结构。
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)