c++cascadeblackberry-10

Catch error when QList index is out of bounds


I am developing an application for BlackBerry 10 and when I try to get the element 2 from a QStringList while this list contains only one element, my application crashes.

I am using the following code to catch this type of error:

try {
    // A code that accesses QStringList with an index out of bounds
}
catch (Exception e) {

}

But the exception is not caught and the application always crashes.

I tried catch (std:exception& e) and catch(...), and it didn't work either.

How can I use the try catch to catch this error?


Solution

  • Accessing a QList out of its range doesn't throw an exception. Instead, it assumes that you already checked that the index is in the range (what happens if this isn't true is explained below).

    Actually, this is not a bad design but a good design of the container class: Sometimes (in most of the cases) you already know that indices are in the range. If Qt should react to out-of-bound accesses by throwing exceptions, this means you want to rely on this check, which means this check has to be done (even if you don't need Qt to check it). What Qt does instead is to assume you provide a valid index. In debug builds, this gets checked with an assertion and if the assertion isn't met your program terminates with a reason (you can track it nicely for debugging), but in release mode this check isn't done at all, so it silently produces undefined behavior if the index was out of bounds by still accessing the raw memory in the data structure. This is as fast as possible, but requires the index to be valid.

    Assertions will terminate your process if they aren't met, meaning you can't "catch" this kind of error. Avoid it in the first place, i.e. test for your index being in range before accessing the list.

    Note that some (maybe all?) container classes also provide an access with a "real" index check (no crash, also in a release build), i.e. with defined and intended behavior when it is out of bounds. For QList, this function is:

    T value(int index, T fallbackValue)
    

    It tries to access the element at index with a bounds check. If your index is not in range (or in associative containers: it was not found), the fallbackValue you have given will be returned. The second parameter defaults to a default-constructed T. Note that this value has to be constructed even if your index is correct. This is why even in cases where you want the check it might be better to do the check manually with a branch, and only construct a default value if needed (in particular if you need to evaluate an expensive expression to construct your fallback value):

    if (index < myList.count())   // We only check upper bound in this scenario
        foo = myList[index];
    else
        foo = expensiveFunctionReturningMyFallbackValue();