为什么重命名我的变量会阻止segfault
Why does renaming my variable prevent a segfault?
我实现了一个单一的深度优先搜索算法来遍历我的图,将迭代器指定到一个起始节点。
文件摘要:
GraphIter
是Graph::iterator
的类型定义Graph
类扩展map<string, Node>
start->second.edges()
返回set<string>
如果start->second.edges()
的大小为0,则此代码会导致分割故障:
(为了简洁起见,我已经截断了不相关的部分,包括递归调用。)
错误代码
void Graph::dfs(GraphIter start)
{
cout << "EDGES SIZE: " << start->second.edges().size() << endl;
for (set<string>::iterator it = start->second.edges().begin();
it != start->second.edges().end(); ++it)
{
GraphIter iter = this->find(*it); // <--- SEGMENTATION FAULT
}
}
现在看看当我把start->second.edges()
拉入一个局部变量时会发生什么:不再有segfault!
以下是不会生成segfault的代码:
良好规范
void Graph::dfs(GraphIter start)
{
set<string> edges = start->second.edges(); // <--- MAGIC TRICK
cout << "EDGES SIZE: " << edges.size() << endl;
for (set<string>::iterator it = edges.begin();
it != edges.end(); ++it)
{
GraphIter iter = this->find(*it);
}
}
因此,不同之处在于,在好的代码中,当字符串集的大小(来自edges()
方法)为0时,在第二种情况下永远不会进入for
循环。但在第一种情况下,for
循环仍然至少执行一次,直到它意识到它不能取消引用it
变量。
为什么这些不同?他们不是在访问记忆的相同部分吗?
因为edges()
按值返回一个set
,所以start->second.edges().begin()
和start->second.edges().end()
将迭代器返回到不同的容器,因为每次调用edges()
都会返回一个新的set
。
通过使用命名变量创建单个副本,可以确保迭代器都来自同一个容器,并且可以有效地从begin()
迭代器到end()
。
可能是start->second.edges()
按值返回std::set<std::string>
。这将导致循环中的迭代器不兼容,并导致未定义的行为。
你的"魔术"
set<string> edges = start->second.edges();
确保在同一个容器"edges"上进行迭代。
您可以通过引用返回Node::edges()
来修复它:
const std::set<std::string>& edges() const { .... }
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 将数组的地址分配给变量并删除
- 为"adjacent"变量赋值时出现问题
- enum是C++中的宏变量还是整数变量
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 用C++中的一个变量定义一个常量
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 你能重载对象变量名本身返回的内容吗
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 尝试通过多个向量访问变量时,向量下标超出范围
- 试图让变量检查数组中的某些内容
- Cpp-Tuple使用带有变量的get
- SegFault在QTCreator上使用GDB检查变量后
- SEGFAULT正在写入堆栈变量
- ctypes/C++segfault访问成员变量
- 为什么重命名我的变量会阻止segfault
- 简单的引用变量赋值导致对象的全局指针出现segfault
- 将字符串变量传递给boost::ASIO读取器/处理程序会导致segfault