朴素的反向字符串迭代无限循环 and/or 断言失败 C++ / Visual Studio 2022

Naive reverse string iteration infinite loop and/or assertion failure C++ / Visual Studio 2022

我正在尝试对字符串进行反向迭代,但在最新的 VS 中遇到 [] 运算符的断言失败。

int foo() {
    std::string s = "s";
    for (int i = (s.size() - 1); i >= 0; i--) {
        std::cout << s[i] << std::endl;
    }
    return 0;
}

注释掉cout行给出无限循环警告,确实进入无限循环:

int foo2() {
    std::string s = "s";
    for (int i = (s.size() - 1); i >= 0; i--) {
        //std::cout << s[i] << std::endl;
    }
    return 0;
}

无论是否在 for 循环中有任何内容,向前迭代都可以正常工作:

int bar() {
    std::string s = "s";
    for (int i = 0; i < s.size(); i++) {
        std::cout << s[i] << std::endl;
    }
    return 0;
}

我使用的是 C++14 标准和用于其他 compilers/older 版本 VS 的相同代码。任何字符串大小都存在相同的问题(尽管这应该无关紧要)。我知道我可以修改代码以使用和取消引用指针而不是使用 int,但想了解为什么这不再起作用,为什么它不安全或不正确,或者我还缺少什么。谢谢!

Commenting out the cout line gives infinite loop warning and indeed enters infinite loop

s.size() 是一个 unsigned long,因此它永远不会小于 0。由于将 unsigned long 分配给 int 而缩小转换的行为是实现定义的行为,尽管将 unsigned long 值 0 分配给 int 时应该不是问题,至少我不这么认为,但谁知道呢,MSVC 确实有它的怪癖。

编译器似乎足够聪明,可以预测当 for 循环的这个特定主体存在时不会有无限循环,这让我相信访问时可能会抛出异常数组,可能越界访问。

使用调试器跟踪 i 的值是了解正在发生的事情的最佳选择。

会不会是您的 int 默认为无符号,因此在 i=0 时递减以得到高值?

正如@PeteBecker 提到的,int 应该被签名并且不应该溢出。但是我的猜测是您的实际代码不使用 int.

这个问题实际上最初是由“auto”i 而不是“int”i 引起的,但没有正确刷新。 Auto 给了我一个 unsigned int 类型,它溢出 [] 运算符,或者一旦 i = 0 循环完成并执行 i-- 就会导致无限循环从零翻转到 18446744073709551615。

谢谢大家的热心回复!