开发者

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?


  1. Foo x = y; and Foo x(y); are equivalent, so use whichever you prefer.

  2. 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.

  3. 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 the end() value just once as the start of the loop. For any container where calculating end() was vaguely expensive, calling it only once may save CPU time. For any halfway decent real-world C++ Standard library, all the end() 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 expensive end() function, there's no benefit to explicitly "caching" end() in optimised code.

      This is interesting, as it means for vector that size() may require a small calculation - conceptually subtracting begin() from end() then dividing by sizeof(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 a typedef, 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 than type 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 of expr, 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 over explicit X::X(double); to match X::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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜