Frank Puffer
Frank Puffer

Reputation: 8215

Why does Scott Meyers recommend to prefer `iterator` to `const_iterator`

In item 26 of his book Effective STL, Scott Meyers recommends to prefer iterator over const_iterator. As I understand, he justifies this mainly by explaining that const_iterator does not work with certain functions like insert or erase.

But isn't that the whole point of a const_iterator, that it does not allow modifying the container? And maybe more importantly, it allows you to express this intention in your code.

Shouldn't he rather recommend to use const_iterator by default and only if you need to modify the container, use iterator?

Upvotes: 2

Views: 724

Answers (2)

Kyle Strand
Kyle Strand

Reputation: 16499

The short answer is that Meyers does consider const_iterators preferable when using an up-to-date implementation of the STL due to improvements made in the C++11 standard.

Before discussing his reasons for giving the anti-const_iterator advice in the first place and explaining what changed, though, I need to clear up a misconception. You write:

isn't that the whole point of a const_iterator, that it does not allow modifying the container?

This is a sensible assumption, but in fact this is not quite the purpose of const_iterator. As Meyers explains in the third edition of Effective C++ (written, notably, before C++11):

Declaring an iterator const is like declaring a pointer const (i.e., declaring a T* const pointer): the iterator isn't allowed to point to something different, but the thing it points to may be modified. If you want an iterator that points to something that can't be modified (i.e., the STL analogue of a const T* pointer), you want a const_iterator[.]

In short, const_iterator doesn't protect against modifying the container, it protects against modifying the contained values. This is why Meyers expects insertto be compatible with const_iterator: it doesn't modify any of the elements already present in the container.

erase is a bit stranger, because it causes a contained element to be destroyed, which is a non-const operation. But note that the element's destructor is not called via the iterator itself; the iterator is merely the means the API provides to specify the item to be erased. Semantically, a const_iterator should be able to serve this purpose as well as an an iterator.


Now, as for the advice in Effective STL and its subsequent retraction, I'll paraphrase and quote some of Effective Modern C++ on the matter. In Item 13, "Prefer const_iterators to iterators", Meyers writes:

...in C++98, const_iterators had only halfhearted support. It wasn't that easy to create them, and once you had one, the ways you could use it were limited....

...there was no simple way to get a const_iterator from a non-const container...

Once you had the const_iterators...locations for insertions (and erasures) could be specified only by iterators. const_iterators weren't acceptable.

He gives an example making extensive use of static_cast to get around these limitations, but points out,

...the code I've shown might not compile, either, because there's no portable conversion from a const_iterator to an iterator, not even with a static_cast. Even the semantic sledgehammer known as reinterpret_cast can't do the job.

He summarizes:

...const_iterators were so much trouble in C++98, they were rarely worth the bother.

These issues were addressed by the C++11 standard. As alluded to in a comment on your question, this standard introduced cbegin and cend, which return const_iterator regardless of whether the container itself is const. Also, insert and erase were given overloads taking const_iterator. This makes const_iterator much easier to use.

Upvotes: 4

BiagioF
BiagioF

Reputation: 9715

The reasons he says in his book are:

• Some versions of insert and erase require iterators. If you want to call those functions, you're going to have to produce iterators. const and reverse iterators won't do

• It's not possible to implicitly convert a const iterator to an iterator, and the technique described in Item 27 for generating an iterator from a const_iterator is neither universally applicable nor guaranteed to be efficient.

But, very important, he continues:

Don't be fooled into thinking that this means const iterators are useless in general. They're not. They're perfectly useful with algorithms, because algorithms don't usually care what kind of iterators they work with. as long as they are of the appropriate category. const iterators are also acceptable for many container member functions. It's only some forms of insert and erase that are picky.

So, as always, it strongly depends on the context and situation.

Upvotes: 3

Related Questions