为什么在 C++11 之后 std::basic_string 的尾后迭代器的取消引用仍然是 UB?

998*_*353 2 c++ iterator stdstring undefined-behavior c++17

众所周知,C++11 添加了一个 null 终止符std::basic_string(这不计入大多数成员函数)。但是当我阅读cpp ref时,我发现对 UB 的取消引用(这一段与 std::vector 的段落end()几乎相同)。为什么会出现这种情况?或者这是 cpp ref 的错误(请提供此文档以进行验证)?

我尝试过 GNU C++,但不幸的是 __gnu_debug 似乎不包含std::string迭代器检查器。Clang++ 的消毒剂也没有。

eca*_*mur 6

正确的; 迭代end()器不能是间接的,即使[data(), data() + size()]是一个闭范围。

据我所知,在调试模式下强制执行此操作的唯一主要编译器是 Microsoft Visual Studio:

#include <string>
int main(int argc, char* argv[]) {
    return *std::string(argv[argc - 1]).end();
}
Run Code Online (Sandbox Code Playgroud)

上面的程序编译后cl.exe a.cpp /EHsc /Zi /MDd /std:c++20 /D_ITERATOR_DEBUG_LEVEL=2给出以下调试断言:

表达式:无法取消引用字符串迭代器,因为它超出范围(例如结束迭代器)

std::string (libstdc++按设计不执行迭代器调试,以允许调试和发布模式之间的 ABI 兼容性;libc++声称执行迭代器调试std::string,但似乎没有捕获此错误。)

标准中出现这种看似不一致的原因是,提供 null 终止符是为了方便需要 null 终止字符串的 C 风格 API;但这些是通过原始字符指针而不是迭代器访问字符串。因此,使尾后迭代器可解引用对此类代码没有任何帮助,并且可能隐藏使用 C++ 样式迭代器时的错误。