使用无效的迭代器是未定义的行为吗?
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
以启用调试断言将检测此问题的标准库实现。
考虑这段代码:
#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
以启用调试断言将检测此问题的标准库实现。