C++分解声明触发ASAN报错求助:二叉树右视图解法异常
为什么C++结构化绑定引用队列元素后调用pop会触发ASAN报错?
我在完成二叉树的右视图题目时,以下代码触发了ASAN报错:
class Solution { public: vector<int> rightSideView(TreeNode* root) { if (root == nullptr) return vector<int>(); int ans[205]; memset(ans, -1, sizeof ans); queue<pair<TreeNode*,int>> q; int ml = 0; q.push({root, 0}); while(!q.empty()) { const auto &[node, level] = q.front(); q.pop(); ml = max(ml, level); if (ans[level] == -1) ans[level]=node->val; if (node->right != nullptr) q.push({node->right, level+1}); if (node->left != nullptr) q.push({node->left, level+1}); } return vector<int>(ans,ans+ml+1); } };
但把const auto &[node,level]=q.front();q.pop();替换为auto pair=q.front(); auto node=pair.first; auto level=pair.second;后,程序运行正常,想知道问题的原因。
问题核心原因:悬空引用导致的未定义行为
- 当你使用
const auto &[node, level] = q.front();时,node和level本质是队列头部pair<TreeNode*, int>对象的成员的引用,它们没有独立存储空间,直接指向队列中那个元素的成员。 - 紧接着调用
q.pop()会将队列头部的元素移除并销毁,原来的pair对象已不存在,node和level就变成了悬空引用。 - 后续访问
node->val、node->right等操作,都是在访问已被销毁对象的引用,属于C++未定义行为,ASAN(AddressSanitizer)检测到这类非法内存访问,因此触发报错。
为什么修改后的写法没问题?
改成auto pair = q.front();时,你把队列头部的pair对象完整拷贝到了局部变量pair中,这个局部变量的生命周期属于当前循环块。即使q.pop()销毁了队列里的原对象,你使用的是局部拷贝的pair及其成员,不存在悬空引用问题,内存访问完全合法,所以ASAN不会报错。
另外,如果把结构化绑定改成值绑定(不加&):auto [node, level] = q.front();,也能避免问题——这种写法会把队列中pair的成员分别拷贝到node和level两个局部变量中,拥有独立生命周期,后续pop不会影响它们的有效性。
内容的提问来源于stack exchange,提问作者Rupa
相关产品推荐
相关产品推荐

