A Beginner’s Bug with C++11 Range-For Loops

This is an interesting bug that may affect C++11 novices. I’m proposing it in a Q&A form below.

Q. I have this old C++ code that uses a for loop to convert an ASCII string to upper-case:

std::string s = "Connie";

// Convert string to upper-case
for (size_t i = 0; i < s.length(); i++) {
  s[i] = std::toupper(s[i]);
}

std::cout << s << '\n';

This code works just fine and prints “CONNIE” as expected.

I tried to modernize this code, using C++11’s range-for loops. I rewrote the previous loop like this:

for (auto ch : s) {
  ch = std::toupper(ch);
}

Unfortunately, it doesn’t work: the output is still the original “Connie” string, not the expected upper-case version.

What’s wrong with that code?

A. The problem is in this line:

for (auto ch : s) {

Using this “auto ch” syntax, at each iteration step, the ch variable contains a copy of the original char in the string.

So, in the body of the range-for loop:

  ch = std::toupper(ch);

at every iteration step you are just converting to upper-case a temporary copy of the original string characters, not the original characters themselves!

What you really want to is iterating through the original string characters in place, instead of operating on temporary copies.

The “auto&” syntax (note the “&”) is what will make it work:

// Iterate through the string characters *in place*.
// NOTE the "&"!!
for (auto& ch : s) {
  ch = std::toupper(ch);
}

I wrote some simple practical advice for range-for loops in this blog post. For more details on using range-for loops, you may want to read this Q&A on StackOverflow.

 

Leave a Reply

Your email address will not be published. Required fields are marked *