C++中从指针类型set中erase元素无效?求解决方法
问题分析与解决
为什么erase(n1)没有生效?
问题出在你自定义的比较器comp上:
- C++的
std::set要求比较函数必须满足严格弱序(Strict Weak Ordering),核心规则包括:对于任意元素x,comp(x, x)必须返回false(反自反性);如果comp(a,b)为true,comp(b,a)必须为false(非对称性)。 - 你写的
return a->val <= b->val违反了反自反性:当a和b指向同一个节点时,a->val <= b->val返回true,这会让set的内部逻辑彻底混乱——它无法正确判断元素是否相等,也无法准确定位要删除的元素。 - 所以当你调用
s.erase(n1)时,set根本找不到n1对应的位置,删除操作实际没执行,集合里的n1依然存在,打印的第二个1其实是n3的val,看起来像是没删掉,本质是删除失败。
正确的解决方法
根据你的需求,分两种情况处理:
情况1:需要按val去重(相同val的节点只存一个)
修改比较器为严格小于<,满足严格弱序:
struct comp{ bool operator()(const Node* a, const Node* b) const{ return a->val < b->val; // 改成严格小于 } };
此时set会自动去重,插入n3时因为它的val和n1相同,会被视为重复元素而无法插入,集合最终只有n1和n2,调用s.erase(n1)就能正常删除。
情况2:允许存储相同val的不同指针(需要保留n1、n3两个节点)
比较器需要先按val排序,val相同时比较指针本身的地址,确保每个不同的指针都是唯一元素:
struct comp{ bool operator()(const Node* a, const Node* b) const{ if(a->val != b->val){ return a->val < b->val; } // val相同时,比较指针地址,保证严格弱序 return a < b; } };
这样set能正确区分n1和n3,调用s.erase(n1)时,set可以通过比较器准确定位到n1,完成删除操作,删除后打印结果会是1,2,。
另外,注意使用完set后要手动释放节点内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Slow Loris
相关产品推荐
相关产品推荐

