c++ - 在单链表中重载赋值运算符
问题描述
我正在学习链表。我创建了一个模板实现,其中包含一个构造函数、一个插入器、一个析构函数、一个复制构造函数和一个重载的赋值运算符。问题是我的测试程序在重载赋值运算符后没有输出任何内容。
对于我的赋值运算符,我使用一个Clear()
函数在复制之前完全清除列表。我把它放在析构函数中并检查它是否工作正常。我还检查了我的复制构造函数,它也运行良好。
文件node.h
:定义节点构建块
#include <iostream>
using namespace std;
template <typename T>
struct Node{
T _item;
Node<T>* _next;
Node() {
_item = T();
_next = NULL;
}
Node(T item){
_item = item;
_next = NULL;
}
// Print the value of a node
friend std::ostream& operator <<(std::ostream& outs, const Node<T> &printMe){
outs << "[" << printMe._item << "]";
return outs;
}
};
文件list.h
:定义链表模板
#include "node.h"
template <class T>
class List {
public:
// default constructor
List();
// Destructor
~List();
// Copy constructor
List(const List<T> ©This);
// Overloading assignment operator
List& operator =(const List& RHS);
// Insert i to the head of the linked list
Node<T>* InsertHead(T i);
// Clear a linked list
void Clear();
// Overload the output operator to print the list
template <class U>
friend ostream& operator <<(ostream& outs, const List<U>& l);
private:
Node<T>* head;
};
这个头文件还提供了这些成员函数的实现:
template <class T>
List<T>::List(){
head = NULL;
}
template <class T>
List<T>::~List(){
Clear();
}
template <class T>
List<T>::List(const List<T> ©This){
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
}
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){ // DOESN'T WORK
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
template <class T>
Node<T>* List<T>::InsertHead(T i){
Node<T>* temp = new Node<T>(i);
temp->_next = head;
head = temp;
return head;
}
// Clear a linked list
template <class T>
void List<T>::Clear(){
Node<T>* current = head;
Node<T>* next = new Node<T>;
while (current != NULL) {
next = current->_next;
delete current;
current = next;
}
head = NULL;
}
template <class U>
ostream& operator <<(ostream& outs, const List<U>& l){
Node<U>* walker = l.head;
while(walker != NULL){
outs << *walker;
outs << "->";
walker = walker->_next;
}
outs << "|||";
return outs;
}
文件main.cpp
:测试类
#include <iostream>
#include "list.h"
using namespace std;
int main() {
List<int> a;
a.InsertHead(17);
a.InsertHead(35);
a.InsertHead(6);
a.InsertHead(54);
a.InsertHead(6);
cout << a <<endl;;
List<int> b;
b.InsertHead(3);
b.InsertHead(2);
cout << b <<endl;;
a = b;
cout << a <<endl; // PROBLEM: NOTHING IS DISPLAYED
cout << b <<endl;
}
我目前遇到的问题是重载赋值运算符函数。下面是当我从复制构造函数复制整个执行并运行时。
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
return *this;
}
输出是:
2->3->|||
但是,当我像下面这样简化代码时,它不会输出任何内容:
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
谁能告诉我为什么它不起作用以及如何有效地简化它?对此,我真的非常感激。
解决方案
问题
由于堆栈溢出,赋值运算符停止一切。
事实上,赋值运算符的实现本身使用赋值运算符,因此它递归调用自身,直到堆栈耗尽:
*this = List<T>(RHS); // OUCH !!
| | |
V V V
<ListT> operator= List<T> ==> cals operator= again !!
解决方案
- 重写运算符,使其不会调用自身。
- 可能克隆每个节点,以避免 2 个列表共享同一个节点,并且第一个释放其节点的列表会导致悬空指针和另一个 UB。
- 不相关,但请避免在标题中使用命名空间。这对以后来说是一个非常糟糕的习惯。
附加提示:本文推荐了一些关于运算符重载的良好而优雅的做法。对于赋值运算符,它建议使用复制构造函数(正如您尝试做的那样),而不是分配(您的问题),交换(有待验证,但在您的情况下交换头部肯定会成功)。
推荐阅读
- r - 有没有办法为多列匹配两个不同的数据框
- mysql - 从另一个表Mysql带来数据属性
- javascript - 添加和删除切换打开和关闭全屏导航的类
- php - 单击按钮后如何更新两个数据库表
- python - 使用 PulP 时,如何从 Gurobi 求解器中检索当前最佳解决方案?
- sql-server - 在系统注册表中找不到正确的类型库 SQL Server 2008 R2 Management Studio 错误
- java - 找不到android studio toString方法
- php - 如何为 php 安装 mssql 驱动程序
- python - Python 2.7 BeautifulSoup 返回不正确的元标记值
- java - Spring Boot 缓存 Hazelcast 返回缓存名称的空列表,并且不会显示任何指标