提问人:998244353 提问时间:10/10/2023 最后编辑:Jarod42998244353 更新时间:10/10/2023 访问量:104
为什么在 C++11 之后,std::basic_string 的 past-the-end 迭代器的取消引用仍然是 UB?
Why is dereference of past-the-end iterator of std::basic_string still UB after C++11?
问:
众所周知,C++11 添加了一个 null 终止符(不计入大多数成员函数)。但是当我阅读 cpp ref 时,我发现 UB 的取消引用(这一段与 std::vector 的段落几乎相同)。为什么会这样?
或者这是 cpp ref 的错误(请提供文档进行验证)?std::basic_string
end()
我尝试过 GNU C++但不幸的是__gnu_debug它似乎不包含迭代器的检查器。Clang++的消毒剂也没有。std::string
答:
6赞
ecatmur
10/10/2023
#1
正确;迭代器不能是间接的,即使它是一个封闭范围。end()
[data(), data() + size()]
据我所知,唯一可以在调试模式下强制执行此功能的主要编译器是 Microsoft Visual Studio:
#include <string>
int main(int argc, char* argv[]) {
return *std::string(argv[argc - 1]).end();
}
上面编译的程序给出了以下调试断言:cl.exe a.cpp /EHsc /Zi /MDd /std:c++20 /D_ITERATOR_DEBUG_LEVEL=2
表达式:无法取消引用字符串迭代器,因为它超出了范围(例如结束迭代器)
(libstdc++ 不执行迭代器调试,以允许调试模式和发布模式之间的 ABI 兼容性;libc++ 声称执行迭代器调试,但似乎没有捕获此错误。std::string
std::string
标准中这种看似不一致的原因是,提供 null 终止符是为了方便需要以 null 结尾的字符串的 C 样式 API;但这些是通过原始字符指针而不是迭代器访问字符串的。因此,使过去的迭代器可取消引用对此类代码没有任何帮助,并且可能会隐藏使用 C++ 样式迭代器时的错误。
评论
std::string::end()
end