mardi 27 décembre 2016

Qt Creator debugger: continuing in a range-based for loop doesn't retrigger breakpoints?

I'm teaching a programming course in a few weeks where we're using Qt Creator as an IDE. 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 Qt Creator, I set a breakpoint on the line containing the range-based for loop:

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

When I ran the program in debug mode, as expected, it triggered the breakpoint and dropped me into the debugger. To progress to the next iteration of the loop, I hit the "continue" button, and to my surprise the program kept on running and never retriggered the breakpoint at the top of the loop.

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 OS or Qt Creator version-specific? I'm running
    • Ubuntu 16.04,
    • Qt Creator 3.5.1 (based on Qt 5.5.1 (GCC 5.2.1 20151129, 64 bit)), and
    • g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609. have
  3. Is there a way to get the debugger to treat the breakpoint on the range-based for loop as a breakpoint on the loop body, not the initialization step?

Aucun commentaire:

Enregistrer un commentaire