Reputation: 8215
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
Reputation: 16499
The short answer is that Meyers does consider const_iterator
s 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 pointerconst
(i.e., declaring aT* const
pointer): theiterator
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 aconst T*
pointer), you want aconst_iterator
[.]
In short, const_iterator
doesn't protect against modifying the container, it protects against modifying the contained values. This is why Meyers expects insert
to 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 erase
d. 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_iterator
s to iterator
s", 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_iterator
s...locations for insertions (and erasures) could be specified only byiterator
s.const_iterator
s 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 aniterator
, not even with astatic_cast
. Even the semantic sledgehammer known asreinterpret_cast
can't do the job.
He summarizes:
...
const_iterator
s 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
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