使用无效的迭代器是未定义的行为吗?

Is Undefined Behavior To Using Invalid Iterator?

考虑这段代码:

#include <iostream>
#include <string>
#include <map>

int  main()
{
  std::map<std::string, std::string>  map = {
    { "ghasem", "another" }
  };
  std::cout << map.find("another")->second << std::endl;
  std::cout << map.size() << std::endl;
}

会编译运行成功(进程return值为0),但是我们看不到map.size()的输出。 -fsanitize=address-fsanitize=undfined 都没有报告任何问题。我用 GCC-11.2.1 和 Clang-13.0.0 编译,两者是一样的。 运行使用 GDB-11.1-5 逐步修改代码将无济于事,所有步骤都将 运行 成功。

但是如果我重新排序最后两行:

#include <iostream>
#include <string>
#include <map>

int  main()
{
  std::map<std::string, std::string>  map = {
    { "ghasem", "another" }
  };
  std::cout << map.size() << std::endl;
  std::cout << map.find("another")->second << std::endl;
}

我会得到一个 Segmentation Fault,现在 ASAN 可以报告这个错误。


我的问题是:代码是否导致某种未定义行为?我怎样才能检测到这些错误?


环境:
  • OS: Fedora 35
  • 编译器
    • 海湾合作委员会 11.2.1
    • 铿锵声 13.0.0
  • 附加编译器标志:
  • 调试器: GDB 11.1-5

映射中没有比较等于"another"的键。因此 map.find("another") 将 return 映射的 .end() 迭代器。在 ->second 中取消引用此迭代器是未定义的行为,因为结束迭代器可能不会被取消引用。

您的代码应检查 return 从 find 编辑的迭代器是否不是结束迭代器,即已找到一个元素。

在调试方面,如果您使用 libstdc++ 作为标准库实现(GCC 和可能的 Clang 就是这种情况),您可以在编译器调用上使用 -D_GLIBCXX_DEBUG 以启用调试断言将检测此问题的标准库实现。