Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Continuing in a range-based for loop doesn't retrigger breakpoints?

I'm teaching a programming course where we'll be using C++. I was putting together a handout about how to use the debugger and wanted to have students step through the execution of this hash code generator for first and last names:

int nameHash(string first, string last){
    /* This hashing scheme needs two prime numbers, a large prime and a small
     * prime. These numbers were chosen because their product is less than
     * 2^31 - kLargePrime - 1.
     */
    static const int kLargePrime = 16908799;
    static const int kSmallPrime = 127;

    int hashVal = 0;

    /* Iterate across all the characters in the first name, then the last
     * name, updating the hash at each step.
     */
    for (char ch: first + last) {
        /* Convert the input character to lower case, then make sure it's
         * between 0 and the small prime, inclusive.
         */
        ch = tolower(ch) % (kSmallPrime + 1);
        hashVal = (kSmallPrime * hashVal + ch) % kLargePrime;
    }
    return hashVal;
}

Using gdb, I set a breakpoint on the line containing the range-based for loop:

(*) for (char ch: first + last)

When I ran the program with gdb and as expected it triggered a breakpoint here. However, if I then continue execution, the breakpoint does not retrigger and the program runs to completion.

I can reproduce this behavior consistently on my system. If I set a breakpoint inside the body of the loop and run until it's hit, if I then add a breakpoint at the top of the loop and hit "continue" the debugger will skip over the loop breakpoint.

I assume that this is probably because a range-based for loop expands out into a series of different initialization steps (I can actually see the temporary variables that were generated in my debug window) and the breakpoint is getting set on the initialization step rather than the loop step. If that's the case, it's understandable but surprisingly counterintuitive.

My current workaround for this issue is to set a breakpoint at the first statement inside the loop rather than at the top of the loop, but this is counterintuitive and, from a pedagogical perspective, really bad advice going forward.

My questions are the following:

  1. Is my analysis correct?
  2. Is this specific to my version of gdb? I'm using
    • Ubuntu 16.04 and
    • g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609. have
  3. Is there a way to get the gdb to treat the breakpoint on the range-based for loop as a breakpoint on the loop body, not the initialization step?
like image 227
templatetypedef Avatar asked May 24 '26 02:05

templatetypedef


1 Answers

You're expecting a one-to-one mapping of source code and execution that doesn't quite exist. The for line isn't "repeated" on each loop iteration; it only introduces and describes how the loop will operate.

It is expected behaviour that a breakpoint on the for line will only be hit once. I don't recall ever using a C, C++, JavaScript, whatever debugger that worked differently.

Put your breakpoint on the first line of the body, instead; it is the body that is repeated.

like image 109
Lightness Races in Orbit Avatar answered May 25 '26 15:05

Lightness Races in Orbit



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!