如何为包装LinkedList的C++模板LStack类实现拷贝函数?
你当前的copy函数实现存在两个核心问题:
- 不可用
memcpy拷贝包含指针成员的自定义类:你的LStack内部持有LinkedList实例,而LinkedList包含head/tail/current三个指针成员,memcpy是浅字节拷贝,会导致副本和原栈的内部指针指向同一块内存,任意一方销毁释放内存后,另一方就会触发野指针错误。 - 返回堆上对象的引用会导致内存泄漏:你在
copy函数内new了栈实例,返回引用后调用方很难感知需要手动释放,极易出现内存泄漏。
以下是完全符合作业限制的解决方案:
第一步:为LinkedList实现拷贝构造函数
因为LStack的功能基于LinkedList实现,且LStack的成员函数可以访问自身私有成员data,我们只需要先给底层LinkedList实现正确的深拷贝构造即可:
// 在LinkedList类的public声明中添加拷贝构造函数声明 LinkedList(const LinkedList<T>& src); // 拷贝构造函数实现 template <typename T> LinkedList<T>::LinkedList(const LinkedList<T>& src) { head = tail = current = nullptr; if (src.isEmpty()) return; // 保存源链表原遍历位置,避免拷贝操作影响源链表的状态 Node<T>* original_current = src.current; // 遍历源链表所有节点,深拷贝到当前链表 src.moveCurrentToHead(); while (true) { addToTail(src.getCurrentData()); if (src.getCurrentData() == src.getTail()) break; src.moveCurrentForward(); } // 恢复源链表的遍历位置 src.current = original_current; }
同时建议补充LinkedList的拷贝赋值运算符,避免后续赋值操作出现浅拷贝问题。
第二步:修改LStack的拷贝逻辑
你可以选择两种方案,都符合作业要求:
方案A:实现LStack拷贝构造(更符合C++习惯,无需单独copy函数)
// 在LStack类的public声明中添加拷贝构造声明 LStack(const LStack<T>& src); // 拷贝构造实现 template <typename T> LStack<T>::LStack(const LStack<T>& src) { // 直接调用LinkedList的拷贝构造完成深拷贝 data = src.data; }
实现后你可以直接在<<运算符重载中直接构造副本:
template <typename T> ostream& operator << (ostream& out, const LStack<T>& LS) { if (LS.isEmpty()) { out << "Stack is empty."; return out; } // 直接用拷贝构造生成副本,不需要单独调用copy函数 LStack<T> LScopy = LS; while (!LScopy.isEmpty()) { out << "("; out << LScopy.peek().get_licence(); out << ", "; out << LScopy.peek().get_charge(); out << ") "; LScopy.pop(); } return out; }
方案B:保留单独copy函数的实现
如果你需要保留单独的copy函数,修改如下:
// 修改LStack类中copy函数的声明,返回值改为对象,参数不需要传自身,加const保证不修改原栈 LStack<T> copy() const; // copy函数实现 template <typename T> LStack<T> LStack<T>::copy() const { LStack<T> res; res.data = this->data; return res; }
调用方式和你原来的代码基本一致,只需要修改调用方法:
LStack<T> LScopy = LS.copy();
额外注意点
- 建议把
LStack的push函数参数改为const T& obj,避免无法传入临时对象/const对象 - 建议把
peek、isEmpty、size这类不修改栈的方法都加const修饰,保证const正确性 - 不需要手动删除
<<运算符中的LScopy,它是局部栈变量,函数执行结束会自动调用析构函数释放资源,不会产生内存泄漏
内容的提问来源于stack exchange,提问作者Daniel Dinosaur
相关产品推荐
相关产品推荐

