C++ 为什么我的超出范围异常没有被捕获

C++ 为什么我的超出范围异常没有被捕获,c++,templates,error-handling,C++,Templates,Error Handling,我是cpp的新手,我正在尝试一些东西。这件事我似乎无法独自解决 #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; }

我是cpp的新手,我正在尝试一些东西。这件事我似乎无法独自解决

#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;
}
现在,行std::printf%d\n,test2.getSecond->d[2];理想情况下,应该抛出超出范围的错误,但事实并非如此。我的皮棉实际上警告我,这也超出了范围。我可以编译并运行程序,它会返回一些垃圾0值

我的问题是:为什么没有抛出错误或者没有捕获错误?我认为没有抛出错误,因为在我运行它时没有打印检查。

因为从未实际到达抛出代码

在此行中:

std::printf("%d\n", test2.getSecond()->d[2]);
getSection返回指向vec对象的指针。然后执行->d操作时,您正在访问vec对象中的d数组。因此,当您将[2]添加到末尾时,您正在访问数组索引2处的元素,而不是调用vec对象的运算符[]

如果您这样重写:

std::printf("%d\n", (*test2.getSecond())[2]);
然后将对vec对象而不是其数组调用运算符[]。请注意,必须取消对getSecond结果的引用。或者,您可以更加详细:

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

,因为从未实际到达抛出代码

在此行中:

std::printf("%d\n", test2.getSecond()->d[2]);
getSection返回指向vec对象的指针。然后执行->d操作时,您正在访问vec对象中的d数组。因此,当您将[2]添加到末尾时,您正在访问数组索引2处的元素,而不是调用vec对象的运算符[]

如果您这样重写:

std::printf("%d\n", (*test2.getSecond())[2]);
然后将对vec对象而不是其数组调用运算符[]。请注意,必须取消对getSecond结果的引用。或者,您可以更加详细:

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

非常好的问题

问题是,当您试图通过索引(如[2])引用数组中的项时,实际上是在引用size*2位置。没有针对它的内置保护,但您始终可以检查\0,因为这是阵列的终点。当您在C/C++中使用数组时,您的工作是确保您不在它们的位置之外。通常,最好将数组保存在结构/类中,并允许使用setter和getter访问其元素,这将处理边界并在违反边界时抛出异常。

问得好


问题是,当您试图通过索引(如[2])引用数组中的项时,实际上是在引用size*2位置。没有针对它的内置保护,但您始终可以检查\0,因为这是阵列的终点。当您在C/C++中使用数组时,您的工作是确保您不在它们的位置之外。通常,最好将数组放在结构/类中,并允许使用setter和getter访问其元素,这将处理边界并在违反这些边界的情况下抛出异常。

边界检查仅使用.at方法完成,而不使用索引运算符[]。->d[2]这将索引d成员,这是一个很好的旧C风格数组。这些方法的文档中对此进行了描述。请参阅并注意:通常,您应该通过常量引用捕获异常&在大多数情况下,不是通过值捕获异常。所以捕获常数std::超出范围&e。不会解决这个问题,只是一条关于最佳实践的建议。test2.getSecond->d[2]应该是*test2。getSecond[2]边界检查只使用.at方法完成,而不是使用索引运算符[]。->d[2]这将索引d成员,这是一个很好的旧C样式数组。这些方法的文档中描述了这一点。请参阅并注意:通常,您应该通过常量引用捕获异常&在大多数情况下,不是通过值捕获异常。所以捕获常数std::超出范围&e。不会解决这个问题,只是一条关于最佳实践的建议。test2.getSecond->d[2]应该是*test2.getSecond[2]