48

Possible Duplicate:
Why use iterators instead of array indices?

string::iterator it;
for (it = str.begin(); it < str.end(); it++) 
    cout << *it;
cout << endl;

Why not:

for (int i = 0; i < str.size(); i++)
    cout << str[i];
cout << endl;

It seems that string::iterator does not provide range check either. Why should we use string::iterator rather than index?

Thanks.

Community
  • 1
  • 1
Jichao
  • 35,945
  • 40
  • 114
  • 183
  • 8
    @jcyang: apart from other's answers, make sure you create a habit of using pre-increment with iterators in loops. i.e. use ++it and not it++. The pre-increment will not create unnecessary temporaries. – Jagannath Jan 03 '10 at 14:50
  • 6
    In addition to Jagannath's comment, prefer `operator!=()` over `operator – jason Jan 03 '10 at 15:14
  • @Jagannath:actually,in this sample code,there are no differences between pre or post increment.i think it only differs when you use the expression in assignment statement. – Jichao Jan 03 '10 at 15:23
  • 1
    @Jason:why?are there any differences? – Jichao Jan 03 '10 at 15:25
  • 2
    @jcyang: The typical implementation of post-increment is `MyIterator operator++(int) { MyIterator temp(*this); ++*this; return temp; }`. This creates an unnecessary temporary whether or not it is assigned. I am implicitly assuming we have also overrode (overridden? overrided?) pre-increment. – jason Jan 03 '10 at 15:26
  • @Jagannath:I thought you were talking about `i`.there is no differece between `++i` and `i++` here.sorry :) – Jichao Jan 03 '10 at 15:28
  • 2
    @jcyang: It is preferred to use ++i. Because if you later change the types used then you don't need to worry about changing the code. You will now always have the most efficient version no matter what the type of the loop variable is. – Martin York Jan 03 '10 at 17:24
  • 7
    @jcyang: Iterators don't (in general) have operator < defined for them. You just happen to be getting lucky that the iterator for std::string does. You should use the operator != when testing to see if you have reached then end. – Martin York Jan 03 '10 at 17:27
  • @Martin York: Thanks. Exactly the right answer. – jason Jan 03 '10 at 17:55

9 Answers9

36

The index can only be used for containers that support random access - direct access to a given position.

The iterator offers a unified way to access any collection/data structure. The flexibility when refactoring your code is immense.

Niels Castle
  • 7,801
  • 30
  • 55
21

Iterators are a standard interface. By using iterators, you can use the same algorithms with different containers. The final decision whether to use them or not is up to you based on usability and readability.

For example, using the standard transform algorithm to covert std::string to uppercase:

std::string str = "A String";
std::transform(str.begin(), str.end(), str.begin(), ::toupper);

will result in str being equal to "A STRING".

Ry-
  • 199,309
  • 51
  • 404
  • 420
Alon
  • 4,798
  • 17
  • 27
  • what about the specific string::iterator?are there any benefits,for example? – Jichao Jan 03 '10 at 15:26
  • @jcyang: Only that if you use iterators, then it works anywhere iterators are expected, and the string can be changed to a char array or a vector or some other container, and your loop will still work. – jalf Jan 03 '10 at 17:21
  • In the example above, the method `std::string::begin()` returns a `std::string::iterator`, as with `std::string::end()`. The benefit is that you can use the `std::transform` algorithm. You can't use it with indices. – Thomas Matthews Jan 03 '10 at 20:12
  • How to iterate by UTF-8 characters (not by 8-bits chars)? Is there UTF-8 iterator for std::strings (I guess the type of the iterator should be uint16_t or uint32_t). How to iterate over Greek letters string "\u03b4\u03b8\u03c6"? – x4444 Jan 08 '21 at 23:49
7

For std::string specifically, i would suggest you use indexes since it supports Random Access and its simpler that way. The only reason its "recommended" to use iterators is because iterators offer a standard interface to access sequences so that if your sequence changed to std::list for example, your iteration code would remain un-affected

lalitm
  • 578
  • 7
  • 11
2

Duplicate of:

  1. Iterators.. why use them?
  2. Why use iterators instead of array indices?

That said, it's a matter of genericity. You can do a lot more with iterators using STL than with array access. Also, if you need to refactor code, and change the string to a vector, list or rope, you wont have to rewrite your code at all.

Finally there's the question of safety in iteration. If you want to access the NEXT character in your loop, with iterators you could do that safely, but increasing the array subscript might segfault on you on the last element, hence needing another check.

Community
  • 1
  • 1
Kornel Kisielewicz
  • 51,225
  • 12
  • 100
  • 147
  • 2
    Trying to access (dereference) the next character in a loop is no safer with iterators than with array subscripts! Both need a check to make sure you're not already at end-of-string. – j_random_hacker Nov 17 '12 at 05:01
1

As stated in this question, size() method is not guaranteed to be O(1)

Community
  • 1
  • 1
Drakosha
  • 11,391
  • 4
  • 36
  • 49
  • 1
    It seems unclear from that thread. A comment mentions that `s.end() - s.begin()` definitely has constant complexity, so one would have to be mad to implement size() with a worse complexity. – UncleBens Jan 03 '10 at 14:58
  • Why? Size can be based on strlen()-alike which is O(stringLength). In order to implement size() in O(1) you will need memory... – Drakosha Jan 03 '10 at 15:28
  • 2
    s.size() cannot be implemented with a strlen()-alike, since std::string may contain any character (including `'\0'`). Also, the string has to keep track where it ends (or its size). Why would you think s.end() and the iterators would be any better, if the string didn't know its length and had to find the end in O(N)? – UncleBens Jan 03 '10 at 16:15
  • 1
    @UncleBens: If the string does not store its size (it is not required to do so but probably does). Then finding the size() would be O(n). As would finding the size using iterators begin() and end() (doing end() - begin() may not be straight arithmetic as there is no requirement for contiguous memory in strings). But the second loop does not calculate the size, it just keeps incrementing the iterator until it reaches then end. – Martin York Jan 03 '10 at 17:35
  • @LokiAstari: The storage for `basic_string` should be contiguous. See [LWG issue #530](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530). – musiphil Mar 27 '13 at 23:28
  • @musiphil: That is an issue report that is just repeating what I said. Its not required (but probably always is), and should be required. I believe (but I am not sure) this was updated in C++11 and is now required. – Martin York Mar 28 '13 at 18:27
  • @LokiAstari: The report says: (1) it was not very conceivable to have discontiguous storage for `basic_string` even under the then-current standard (in 2005), but (2) it was not very clearly stated anyway, and (3) the fix (requiring contiguous storage explicitly) was accepted into the Fall 2008 Committee Draft. So, contiguous storage is required in C++11. – musiphil Mar 28 '13 at 20:51
  • @musiphil: Which is **exactly** what I said in my original and last comment(thus you are not adding anything intelligent to this discussion). Note: Just because a defect report says it was integrated into the standard does not mean it made it into the final standard. It can subsequently be removed at a later meeting. The only acceptable way to say it is in the standard is to quote the standard. (Note when doing this it is usually best to also include the version of the standard). – Martin York Mar 29 '13 at 14:18
  • @musiphil: You can get a copy here: http://stackoverflow.com/a/4653479/14065 – Martin York Mar 29 '13 at 14:24
  • @LokiAstari: You said in your comment, "there is no requirement for contiguous memory in strings", which reads like an assertion (of "no requirement"). I wanted to add the information that things might have been somewhat vague but that they are now resolved clear (that it is required). People may also be interested in the process things are fixed in the standard. Is this anything duplicate or unintelligent? – musiphil Mar 29 '13 at 20:07
  • @LokiAstari: You are right that the defect report doesn't guarantee acceptance into the standard, but at least it shows the decision made by the committee at the time it was considered. I do have many versions of the working draft of the standard, and every version I have since N2960 has the requirement for contiguous storage. (It would have been much easier to just quote the standard, where I just know where things are; searching for the right defect report takes more time but I wanted to show the discussion that took place to make the change happen.) – musiphil Mar 29 '13 at 20:12
  • @musiphil: There was no requirement. It was added in C++11. – Martin York Mar 29 '13 at 20:34
  • @LokiAstari: I didn't say otherwise. YOU said "There _is_ no requirement" (in the present tense). – musiphil Mar 30 '13 at 05:51
  • @musiphil: On Jan 10 2010! So at the time there was no requirement. – Martin York Mar 30 '13 at 13:47
  • @LokiAstari: You are right, the posting date slipped my eyes. LWG issue #530 I referred to says that there was no formal requirement. I believe the update to the requirement is helpful to readers. – musiphil Mar 30 '13 at 17:58
1

In cases where you don't know which class you're iterating over (because it's a template argument), you should use an iterator because not every class that provides an iterator also provides [] (and not every class that does provide [], provides one which works in O(1) time). So by using iterator you'll make sure that the function will work with as many classes as possible (though not with C arrays).

In this specific case, I see no reason to prefer one over the other except personal preference or maybe premature optimization.

sepp2k
  • 341,501
  • 49
  • 643
  • 658
0

Both works.

The main reason would be consistency: you're iterating over a collection or the characters of a string the same way, by requesting an iterator and making it advance.

I would not say the implementation details of ++it resulting in a pointer increment compared to str[i] involving pointer arithmetics is worth mentioning. And range checking are implementation detail as well.

Gregory Pakosz
  • 65,227
  • 16
  • 134
  • 162
0

Iterators are safer and provide more flexibility as posted by someone else too.In additon an index only can be used for containers that (efficiently) support random access (i.e. direct access to an element at a given position).An iterator is a more general concept. Iterators offer efficient traversal of linked lists, files, and a number of other data structures. It often leads to the generation of more efficient code.

Prasoon Saurav
  • 85,400
  • 43
  • 231
  • 337
-1

In C++, you can do many things in many different ways. This is one more example. In this case, there is no difference which method to use. But in general, iterators are faster, safer and provide more flexibility amond different types of containers.

alemjerus
  • 7,131
  • 2
  • 30
  • 40