I am currently "modernizing" my toy-compiler code to use as many C++11 features as possible to learn how to write modern C++. While looking at my code, searching for things to modernise I found this construct:
for (size_t i = 0; i < _vector.size(); i++) {
for (size_t j = 0; j < _vector[i].length(); j++) {
_vector is a std::vector<std::string>
containing the source code of the file which needs to be compiled. Each std::string
in the vector is a line of code which needs to be compiled. Before compilation takes place the compiler checks whether the code to be compiled has any syntax errors, and the first step of this check is to look out for missing semicolons. I do this by looking at each character one by one and checking if said character is a semicolon. If it is, I perform a check whether the semicolon is needed by building a kind of mini-syntax-tree and thereby determining if it is necessary. I currently access each character with _vector[i][j]
which is very reminiscent of ANSI-C (this is how you access each character in an array of char*) and I want to replace this with iterators. As far as I know, an Iterator is a pointer-like construct which points to an element in a container/sequence/whatever. Applying the pointer analogy I deduced that an std::vector<std::string>::iterator
points to a string in a vector, therefore a theoretical std::vector<std::string>::iterator::iterator
would point to a single character in a string object. But because there isn't such thing in the STL the pointer analogy isn't of much use here. So my question is: How do I access each Character within a std::vector<std::string>::iterator
?
An iterator
behaves like a pointer. So in your case, you can dereference the first iterator to get the string
and use a std::string::iterator
to access each character.
Another way is to use operator->()
to directly get at the std::string::iterator
, e.g.
for (std::vector<std::string>::iterator i = _vector.begin(); i != _vector.end(); ++i) {
for (std::string::iterator j = i->begin(); j != i->end(); ++j) {
/* ... */
}
}
With C++11, you can simplify this to
for (auto i = _vector.begin(); i != _vector.end(); ++i) {
for (auto j = i->begin(); j != i->end(); ++j) {
/* ... */
}
}
As @LightnessRacesinOrbit mentioned and @MateuszGrzejek already showed, the next step would be moving to a Range-based for loop. A loop iterating from the first begin()
to the last end()
element
for (auto i = _vector.begin(); i != _vector.end(); ++i) {
// Do something with string (*i)
can be written as
for (auto &s : _vector) {
// Do something with string (s)
or, if you don't modify string, make it const
for (const auto &s : _vector) {
// Do something with string (s)