简体   繁体   中英

Why is my out_of_range exception not being caught

I am new to cpp and I am trying out several things. This one I can't seem to figure out on my own.

#include <cstdio>
#include <stdexcept>

template <class E, class V> 
struct Pair {
    E first;
    V second;

    Pair(E fst, V snd) : first(fst), second(snd) {}

    E getFirst() { return first; }
    V getSecond() { return second; }
};

template <class t, unsigned dim> 
struct vec {
    t d[dim];

    static constexpr int dimen = dim;

    t &operator[](unsigned n) {
        std::printf("dim: %d %d\n", dim, n);
        if (n >= dim) {
            std::printf("checking %d\n", n);
            throw std::out_of_range("vector index is out of range");
        }
        return d[n];
   };
};

int main() {

    try {
        Pair<int, vec<int, 2> *> test2(2, new vec<int, 2>{1, 2});
        std::printf("%d\n", test2.getSecond()->dimen);
        std::printf("before\n");
        std::printf("%d\n", test2.getSecond()->d[2]); // it seems like the compiler kind of ignores this
    } catch (std::out_of_range e) {
        std::printf("Caught!!");
    }
    return 0;
}

Now, the line std::printf("%d\n", test2.getSecond()->d[2]); should ideally throw the out_of_range error, but it is not. My linter actually warns me that this is out of range also. I can compile and run the program and it returns some garbage 0 value.

My question is: why is either the error not being thrown or the error not being caught? I think the error is not being thrown because checking is not printed when I run it.

Because the throw code is never actually reached.

In this line here:

std::printf("%d\n", test2.getSecond()->d[2]);

getSection() returns a pointer to the vec object. When you then do ->d you are accessing the d array, within the vec object. Thus, when you add the [2] to the end, you are accessing the element at index 2 of the array, and are not calling operator[] of the vec object.

If you rewrite like this:

std::printf("%d\n", (*test2.getSecond())[2]);

Then the operator[] will be called on the vec object, and not its array. Note that you have to dereference the result of getSecond() . Alternatively, you can be more verbose:

std::printf("%d\n", test2.getSecond()->operator[](2));

Working example: https://godbolt.org/z/YWKzPz

Very good question!

The issue is that when you try to reference an item in an array via index, such as [2], you are actually referring to the size * 2 location. There is no built-in protection against it, but you can always check for \0 as that's where your arrays end. When you use arrays in C/C++, it is your job to make sure you are not outside of their location. It's generally a good idea to keep your array inside your structure/class and allow reaching its elements with setters and getters, which would handle the bounds and throw exceptions if those are violated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM