C++ Partition类makeSet返回迭代器main中解引用抛异常修复
问题背景
实现了Partition分区合并结构,该结构支持创建集合并返回集合对应的位置标识,代码中Partition类内部嵌套了listSet类。
故障现象与疑问
- 在
makeSet()函数内部可以正常输出对应位置的元素 - 当函数返回集合位置后,在
main()函数中尝试输出该位置的元素时会抛出异常 - 不确定
makeSet()的返回值数据类型定义是否正确,咨询修复方案,以及是否需要将makeSet()的返回值改为指针类型
复现代码
#ifndef LISTSET_H #define LISTSET_H #include <iostream> #include <vector> using namespace std; template<typename E> class Partition { public: typedef typename vector<E>::iterator Itr; // 定义迭代器类型 public: template <typename E> class listSet // 嵌套listSet类 { private: vector<E> L; int size; public: listSet() { size = 1; } int getSize() { return size; } Itr insert(E e) /*返回元素位置*/ { L.push_back(e); Itr p = L.begin(); //cout << *p << endl; // 此处打印正常 return p; } }; public: Itr makeSet(E e); }; template<typename E> typename Partition<E>::Itr Partition<E>::makeSet(E e) { listSet<E> set; Itr p = set.insert(e); cout << *p << endl; // 此处打印正常 return p; } #endif int main() { Partition<int> set1; Partition<int>::Itr p1, p2, p3; p1 = set1.makeSet(1); p2 = set1.makeSet(2); cout << *p1 << endl; // 此处触发异常 }
报错参考

故障根因
该异常是典型的悬空迭代器问题,和返回值是否改为指针无直接关联:
makeSet()中定义的listSet<E> set是栈上局部对象,函数执行完成返回时,该对象会被立刻析构,其内部存储元素的vector<E> L占用的内存会被系统回收- 返回的迭代器
p指向这块已经被释放的内存:函数内部打印时局部对象尚未析构,因此可以正常输出;回到main函数时内存已失效,访问就会触发段错误/异常 - 代码额外隐患:嵌套类
listSet上重复定义的template <typename E>会遮蔽外层Partition类的模板参数E,存在类型匹配风险;同时Partition类没有持久化存储创建出的集合对象,完全无法实现分区合并的基础逻辑。
修复方案
不需要将返回值改为指针,核心是保证迭代器指向的内存生命周期长于迭代器的使用周期:
- 在Partition类中添加成员容器存储所有创建的listSet对象,保证这些对象的生命周期和Partition实例一致,不会随
makeSet函数返回被销毁 - 移除嵌套类多余的模板声明,避免模板参数遮蔽问题
- 遵守vector迭代器使用规则,只要vector不发生扩容、析构,返回的迭代器就可以正常访问
修正后的核心代码示例:
template<typename E> class Partition { public: typedef typename vector<E>::iterator Itr; // 移除嵌套类多余的template声明,避免参数遮蔽 class listSet { private: vector<E> L; int size; public: listSet() { size = 1; } int getSize() { return size; } Itr insert(E e) { L.push_back(e); return L.begin(); } }; private: // 持久化存储所有创建的集合,生命周期与Partition实例绑定 vector<listSet> sets; public: Itr makeSet(E e); }; template<typename E> typename Partition<E>::Itr Partition<E>::makeSet(E e) { // 新集合存入成员容器,不会随函数返回销毁 sets.emplace_back(); Itr p = sets.back().insert(e); cout << *p << endl; return p; }
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

