在将变量声明为引用时,堆在释放后使用

heap-use-after-free when declaring a variable as a reference

本文关键字:释放 变量 声明 引用      更新时间:2023-10-16

下面粘贴的代码返回一个heap-use-after-free错误。当我删除引用符号'&'时在具有coord &c = q.front(); q.pop();的线路上,错误被解决。

据我所知,当没有更多引用时,C++垃圾收集器会删除我从q.front((中检索到的coord。尽管这里似乎coord &c中的C在从队列中弹出后立即从堆中删除,并且试图在下一行访问C会导致错误。

然而,这种情况并不是每次都会发生,所以我想知道为什么会发生这种情况。

class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if(grid.size() == 0) return 0;
typedef pair<int,int> coord;
queue<coord> q;
const int m = grid.size();
const int n = grid[0].size();
int i_in[] = {0,0,1,-1};
int j_in[] = {1,-1,0,0};
int ans = 0;
for(int i = 0; i < m; ++i)
{
for(int j = 0; j < n; ++j)
{
if(grid[i][j] == '1')
{
++ans;
q.push(coord(i,j));
while(q.size() > 0)
{
coord &c = q.front(); q.pop();
grid[c.first][c.second] = '*';
for(int k = 0; k < 4; ++k)
{
int newi = c.first + i_in[k];
int newj = c.second + j_in[k];
if(newi >= 0 && newi < m &&
newj >= 0 && newj < n && 
grid[newi][newj] == '1')
{
q.push(coord(newi, newj));
}
}
}
}
}
}
return ans;
}
};
coord &c = q.front(); 

^^^此行将c设置为引用当前位于队列前面的pair<int,int>

q.pop();

^^^这一行删除队列前面的项目,在过程中销毁它(。因此,在这一行返回后,c引用指向一个无效对象,这意味着尝试使用c将调用未定义的行为。

然而,这种情况并不是每次都会发生,所以我想知道为什么会发生这种情况。

发生的是未定义的行为,当您尝试使用悬挂引用时会调用该行为。关于未定义行为的有趣之处在于;事情似乎进展顺利"是一个有效的结果,就像发生的任何其他事情一样——因为一旦你调用了未定义的行为,所有的赌注都会被取消,编译器编写者就没有任何义务让程序从此正确运行,世界就崩溃了。

要解决这个问题,您可以删除"与"符号(就像您所做的那样(,这样就没有引用,因此就不会出现悬空引用问题(因为您已经将队列的pair<int,int>对象复制到了局部变量中(;或者,您可以将对q.pop()的调用向下移动到while循环的末尾,这样它只会在您对c引用的所有使用都已执行之后发生。