what is the better way to write iterators for a loop in C++
For a very simple thing, like for example to print each element in a vector, what is the better way to use in C++?
开发者_运维问答I have been using this:
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
before, but in one of the Boost::filesystem examples I have seen this way:
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
For me it looks more complicated and I don't understand why is it better then the one I have been using.
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector?
Does i != values.end()
make the iterating slower?
Or is it const_iterator
vs iterator
? Is const_iterator faster in a loop like this?
Foo x = y;
andFoo x(y);
are equivalent, so use whichever you prefer.Hoisting the
end
out of the loop may or may not be something the compiler would do anyway, in any event, it makes it explicit that the container end isn't changing.Use const-iterators if you aren't going to modify the elements, because that's what they mean.
for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
/* ... */
}
In C++0x, use auto
+cbegin()
:
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
(Perhaps you'd like to use a ready-made container pretty-printer?)
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)
For me [the latter, seen in boost] looks more complicated and I don't understand why is it better then the one I have been using.
I'd say it would look more complicated to anybody who hasn't got some specific reason for liking the latter to the extent that it distorts perception. But let's move on to why it might be better....
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector? Does i != values.end() make the iterating slower?
it_end
Performance:
it_end
gets theend()
value just once as the start of the loop. For any container where calculatingend()
was vaguely expensive, calling it only once may save CPU time. For any halfway decent real-world C++ Standard library, all theend()
functions perform no calculations and can be inlined for equivalent performance. In practice, unless there's some chance you may need to drop in a non-Standard container that's got a more expensiveend()
function, there's no benefit to explicitly "caching"end()
in optimised code.
This is interesting, as it means forvector
thatsize()
may require a small calculation - conceptually subtractingbegin()
fromend()
then dividing bysizeof(value_type)
(compilers scale by size implicitly during pointer arithmetic), e.g. GCC 4.5.2:
size_type size() const
{ return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
Maintenance: if the code evolves to insert or erase elements inside the loop (obvious in such a way that the iterator itself isn't invalidated - plausible for maps / sets / lists etc.) it's one more point of maintenance (and hence error-proneness) if the cached
end()
value also needs to be explicitly recalculated.
A small detail, but here
vec
must be atypedef
, and IMHO it's often best to use typedefs for containers as it loosens the coupling of container type with access to the iterator types.type identifier(expr)
Style and documentary emphasis:
type identifier(expr)
is more directly indicative of a constructor call thantype identifier = expr
, which is the main reason some people prefer the form. I generally prefer the latter, as I like to emphasise the sense of assignment... it's visually unambiguous whereas function call notation is used for many things.Near equivalence: For most classes, both invoke the same constructor anyway, but if
type
has an explicit constructor from the type ofexpr
, it will be passed over if=
is used. Worse still, some other conversion may allow a less ideal constructor be used instead. For example,X x = 3.14;
, would pass overexplicit X::X(double);
to matchX::X(int)
- you could get a less precise (or just plain wrong) result - but I'm yet to be bitten by such an issue so it's pretty theoretical!
Or is it const_iterator vs iterator? Is const_iterator faster in a loop like this?
For Standard containers, const_iterator
and iterator
perform identically, but the latter implies you want the ability to modify the elements as you iterate. Using const_iterator
documents that you don't intend to do that, and the compiler will catch any contradictory uses of the iterator that attempt modification. For example, you won't be able to accidentally increment the value the iterator addresses when you intend to increment the iterator itself.
Given C++0x has been mentioned in other answers - but only the incremental benefit of auto
and cbegin
/cend
- there's also a new notation supported:
for (const Foo& foo: container)
// use foo...
To print the items in a vector, you shouldn't be using any of the above (at least IMO).
I'd recommend something like this:
std::copy(values.begin(), values.end(),
std::ostream_iterator<T>(std::cout, "\n"));
You could just access them by index
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]);
}
prints out: 10 11 12
I don't think it matters. Internally, they do the same thing, so you compiler should optimise it anyway. I would personally use the first version as I find it much clearer as it closely follows the for-loop strucutre.
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
精彩评论