今天在做934.最短的桥这题的时候遇到了heap-use-after-free问题。题目意思很简单,给一个01矩阵表示地图,地图里有且仅有两个由若干值为1的相连格子组成的岛屿,两个岛屿之间的距离大于等于1,让求两个岛屿之间的最短距离。于是我决定dfs标记第一个岛屿,并记录岛屿边缘格子,然后以边缘格子为开始一圈一圈向外进行多源bfs扩展,每扩展一圈两岛屿见距离加一,直至与另一个岛屿相遇。
这是代码:
class Solution {
constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
public:
int shortestBridge(vector<vector<int>>& grid) {
//计算数组长宽,使用mark标记岛屿格子
int m = grid.size(), n = grid[0].size(), mark = 2;
queue<pair<int, int>> q;//用于BFS的队列
function<void(int, int)> dfs = [&](int i, int j) {//dfs函数
grid[i][j] = mark;//每遍历一个格子,标记之,防止重复遍历
bool isBorder = false;
//用于标记格子是否在岛屿边界,
//如果在岛屿边界入队用于后续BFS求两岛间距
for (const auto& [iOfs, jOfs] : direction) {//依次dfs四个方向上的陆地格子
int x = i + iOfs, y = j + jOfs;//邻居格子坐标
if (x >= 0 and x < m and y >= 0 and y < n) {//坐标合法性判断
if (grid[x][y] == 1) dfs(x, y);//如果邻居格子值为1,dfs之
else if (grid[x][y] == 0) isBorder = true;//否则本格子是岛屿边界
}
}
if (isBorder) q.emplace(make_pair(i, j));//如果本格子是岛屿边界,入队之
};
for (int k = 0; k < m; ++k) {//dfs第一个岛屿并入队其边界格子
for (int z = 0; z < n; ++z) {
if (grid[k][z] == 1) {
dfs(k, z);
++mark;
break;
}
}
if (mark == 3) break;
}
//存答案,以及bfs需要用到的队列大小,当前格子计数
int ans = 0, size = q.size(), count = 0;
while (!q.empty()) {//当队列非空,bfs扩展边界直至与另一个岛屿接触
auto& [i, j] = q.front();//获取队头格子坐标
q.pop();//将其出队
if (ans >= 5) cout << 'a' << " ";//断点a
//向格子四周拓展边界
for (const auto& [iOfs, jOfs] : direction) {
if (ans >= 5) cout << 'b' << " ";//断点b
int x = i + iOfs, y = j + jOfs;
if (ans >= 5) cout << 'c' << " ";//断点c
if (x >= 0 and x < m and y >= 0 and y < n) {
if (ans >= 5) cout << 'd' << " ";//断点d
if (grid[x][y] == 1) return ans;
else if (grid[x][y] == 0) {
if (ans >= 5) cout << 'e' << " ";//断点e
grid[x][y] = mark;
if (ans >= 5) cout << 'f' << " ";//断点f
q.emplace(make_pair(x, y));
}
}
}
++count;//记录当前边界已拓展节点数量
if (count == size) {//如果当前边界已拓展完毕
size = q.size();//更新新边界节点数量
count = 0;//初始化计数器
++ans;//两岛屿间距加一
}
cout << ans << " ";//断点g兼ans值监视
}
return ans;//返回答案
}
};然后对于这个测试用例:
vector<vector<int>> v = {
{1,0,1,1,0,0,0,0,0,0},
{1,1,1,1,1,1,0,0,0,0},
{0,1,1,0,1,1,0,0,0,0},
{0,0,1,1,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,1,1,1},
{0,0,0,0,0,0,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1}
};系统报了heap-use-after-free错误:

这个错误之前也遇到过,不过大多是在涉及链表、树的题目里,因为那些题目都要使用堆空间内存,之前也都解决了。
字面意思大概是:使用了已释放的堆内存?可是我这代码也没有哪里释放堆空间内存然后再访问啊。
好嘛,于是粘到IDE里一调试,喜闻乐见,“我电脑上好好的啊!”。
由于穷没开会员不能在线单步调试,于是只能cout大法手动打断点调试,具体看代码里的那些cout哈哈哈。
然后运行结果出来了:

由于没有触发断点c,那看来就是这里出问题了:

啊,真相大白,原来是pop()以后系统把空间释放了,也不管我还有没有引用指向他,真不智能!
原本是为了节省拷贝开销使用结构化绑定引用,结果得不偿失,调错调半天。
把pop()后置再运行一次,好了:

记录一下,免得下次再犯。
