Checked Iterators

Introduction

Checked iterators are something I have known about for a while but never really bothered to use or understand better, until Microsoft Visual C++ 2005 was released. It came with a checked version of the Standard Library even in release mode and when porting the code from other compilers, I saw in practice both good and bad sides of using checked iterators. After working with checked iterators for a year and doing some research on the topic, I feel it is a good time to share the knowledge I gathered with the Code Project community. The article is structured as a series of questions and answers in an attempt to be short and an easy read.

Questions and Answers

What are checked iterators?

Checked iterators offer checked access to containers and other ranges. They are typically aware of the owning container and are able to catch some run-time errors that often lead to undefined behavior and then do something that is well-defined, like throwing an exception or terminating the application. This is particularly useful in avoiding security-related problems such as stack and heap overflows.

What kind of errors do checked iterators detect?

That really depends on their implementation. Some of the common errors they can catch are:

Uninitialized iterators:

vector<int>::iterator it;
it++;

Out of range access:

vector<int>::iterator it = vec.end();
it++;

Comparing iterators from different ranges or containers:

for (it = vec1.begin(); it != vec2.end(); ++it)

Can checked iterators detect other types of errors, such as invalid data in containers/ranges?

Yes. For instance, the UTF-8 CPP library version 2.0 or later has checked iterator adapters that are able to detect invalid utf-8 sequences:

Note that we passed the valid range boundaries as parameters to the constructor of the iterator adapter.

Are there checked containers as well, and if yes what are they good for?

Just as checked iterators keep track of their containers, containers can keep track of the iterators. That enables catching errors such as use of invalidated or "dangling" iterators:

vector<int> it = vec.begin();
vec.clear();
it++;

Is there an easy way to turn an unchecked iterator into a checked one?

Depends. Some STL implementations, like Dinkumware and STLPort offer both checked and unchecked versions, and switching between them is a simple matter of setting specific macros to a desired value. This is particularly handy if you want to use checked iterators in the debug mode and unchecked ones in the release mode, which is a pretty common scenario.

Other than that, you can write a checked iterator adapter that would turn an unchecked iterator into a checked one. In his classic book The C++ Programming Language, Bjarne Stroustrup gives an example of such an iterator adapter. In general, it could be declared something like:

Of course, such adapters are a poor man's replacement for a full-fledged checked STL implementation, but still may be very helpful.

Are there downsides to using checked iterators?

Yes - performance. Checked iterators are fatter and slower than their unchecked counterparts, and the difference in speed (rarely in memory footprint) can be significant. Sometimes it is a good idea to use checked iterators only during development and the first round of testing, and ship the software with unchecked iterators, but that really depends on a concrete situation.

Does Microsoft Visual C++ come with checked iterators?

Yes. In version 8.0 (VC++ 2005) the iterators and containers are checked by default even in release builds. To turn the checked iterators off, the _SECURE_SCL macro must be set to 0. By default, in case an error is detected, the program gets terminated by calling invalid_parameter. This behavior may be changed by setting the _SECURE_SCL_THROWS to 1, and in this case checked iterators throw standard exceptions in case of error.

Conclusion

Checked iterators are a tool you should know about and use appropriately, at least during development.

References

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Do you mean examples of implementing checked operators? As I mentioned in the article, you can find one such sample implementation in the Stroustrup's book. This article is about using checked iterators, not implementing them.

Ahh, And I heard rumors that Dinkumware was in pretty bad shape... I have been using stlport for many years and I have never had a single problem but I guess since nothing is broken and I do not rush to upgrade on every single new release.

Good introduction to checked iterators! I have some remarks to your article (disclaimer: haven't looked at Microsoft's checked iterator yet):

1. check on advance vs. check on accessYour article describes 'check on advance' rather than 'check on access' for iterators, i.e. you check each ++i, not each *i.

2. is it not allowed to compare iterators from different ranges or containers? In your example it clearly is a bug. But I'm not sure whether the C++ Standard forbids those comparisons.

3. checked iterators in Release mode in VC++ 8.0? IMO, iterators should not be checked in Release mode simply because you should never check for program errors in Release mode. Checked iterators detect program errors (a.k.a. bugs), not e.g. invalid user input. It's the wrong default to turn checking on in Release mode. Moreover, throwing an exception e.g. for 'out of bounds' changes the STL interface and is therefore highly questionable.

1. check on advance vs. check on accessYour article describes 'check on advance' rather than 'check on access' for iterators, i.e. you check each ++i, not each *i.

In general, they are usually checked for both. I just gave examples for advance.

Roland Pibinger wrote:

2. is it not allowed to compare iterators from different ranges or containers? In your example it clearly is a bug. But I'm not sure whether the C++ Standard forbids those comparisons.

Not sure what the Standard has to say about this, but it seems a pretty common practice to check for the range. It is hard to imagine a situation where it wouldn't point to a bug.

Roland Pibinger wrote:

3. checked iterators in Release mode in VC++ 8.0? IMO, iterators should not be checked in Release mode simply because you should never check for program errors in Release mode. Checked iterators detect program errors (a.k.a. bugs), not e.g. invalid user input. It's the wrong default to turn checking on in Release mode. Moreover, throwing an exception e.g. for 'out of bounds' changes the STL interface and is therefore highly questionable.

I tend to agree[^] At my work, we turn them off in the release mode, and the speed difference is just amazing. I believe the MS guys are paranoid about buffer overruns, and that's why they keep them on in the release mode.