Перегрузка оператора присваивания в односвязном списке
Я узнаю о связанном списке. Я создал реализацию шаблона с конструктором, вставкой, деструктором, конструктором копирования и перегруженным оператором присваивания. Проблема в том, что моя тестовая программа ничего не выводит после перегрузки оператора присваивания.
Для моего оператора присваивания я использую 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;
}
Может кто-нибудь сказать мне, почему это не работает и как это упростить? Я очень ценю это.
1 ответ
Эта проблема
Оператор присваивания останавливает все из-за переполнения стека.
Фактически, ваша реализация оператора присваивания сама использует оператор присваивания, так что он вызывает себя рекурсивно, пока стек не будет исчерпан:
*this = List<T>(RHS); // OUCH !!
| | |
V V V
<ListT> operator= List<T> ==> cals operator= again !!
Решение
- Перепишите оператор так, чтобы он не вызывал сам себя.
- Возможно, клонируйте каждый узел, чтобы избежать того, что два списка совместно используют один и тот же узел, а первый, освобождающий его узел, вызывает висячие указатели и UB для другого.
- Не связано, но, пожалуйста, избегайте использования пространств имен в заголовках. Это очень плохая привычка на потом.
Дополнительный совет: эта статья рекомендует некоторые хорошие и элегантные методы для перегрузки операторов. Для оператора присваивания он предлагает использовать конструктор копирования (как вы пытаетесь это сделать), но вместо присваивания (ваша проблема) замена (необходимо проверить, но замена головок в вашем случае, безусловно, поможет).