std::out_of_range异常未被抛出。

3
   // The following code works fine, throwing a std::out_of_range exception:
    
    std::vector<double> vd{ 1.5 };
    
        try {
            int i{ -1 };
            double d = vd.at(i); // exception is thrown
        }
        catch (std::out_of_range& re) {
            std::cout << "Exception is " << re.what() << std::endl; // invalid vector subscript
        }

     

如果我在for循环中使用无效索引访问向量元素,即使我使用了.at(),也不会抛出std::exception异常。为什么没有抛出std::out_of_range异常?

// in a for loop, this does not throw the exception!

std::vector<double> vd{ 1.5 };

    try {
        for (int i = -1; i < vd.size(); ++i) 
            double d = vd.at(i); // exception is not thrown. Why?

    }
    catch (std::out_of_range& re) {
        std::cout << "Exception is " << re.what() << std::endl; // exception is not thrown
    }
1个回答

15

由于循环不执行,-1 < vd.size() 为假。

size() 返回一个 无符号 值。因此,在比较两个数字之前,-1 被转换为无符号值。这种转换是通过模最大的 unsigned 值加一来进行的,这意味着 -1 被转换为最大可能的 unsigned 值。然后将其与向量的大小进行比较,而这个比较永远为假。

由于有符号/无符号比较存在以上原因,它们是有问题的。尽管有定义,但如果有符号值为负数,它们不会按照预期的数学方式工作。您的编译器应该会警告您出现了这个问题。


因此,感谢您出色的解释,“for (int i = -1; i < static_cast<int>(vd.size()); ++i)”将产生异常。非常感谢。 - ByronB
1
@ByronB 是的,它会。值得注意的是,当您调用 at 时,同样会发生从有符号到无符号的转换,因为它需要一个无符号参数。 - john
1
@ByronB 是的,向量索引是无符号的,因此太低的索引是不可能的。但是(除非您的向量绝对庞大),有符号到无符号的转换规则确保负索引始终太大。 - john
1
@ByronB 个人观点,我认为混合有符号和无符号值产生的反直觉结果不值得。如果语言没有任何无符号数据类型会更好。只有在非常专业的情况下才需要使用无符号类型,但是由于粗心地混合有符号和无符号类型而导致的重大错误很容易出现。然而,这似乎是少数人的观点。 - john
所以你说使用.at(-1) 时未抛出 std::out_of_range 异常是因为索引值太低,而是因为在 32 位机器上 size_t = 4 字节的情况下,将 int {-1} 转换为无符号整数的 size_t 后,由于 at() 的原因导致索引值过高,例如 4294967295。非常感谢您提供这个深刻的见解,真是太好了。 - ByronB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接