简体   繁体   English

在单向链表中重载赋值运算符

[英]Overloading assignment operator in Singly Linked List

I'm learning about linked list.我正在学习链表。 I created a template implementation, with a constructor, an inserter, a destructor, a copy constructor and an overloaded assignment operator.我创建了一个模板实现,其中包含一个构造函数、一个插入器、一个析构函数、一个复制构造函数和一个重载赋值运算符。 The problem is that my test programme doesn't output anything after overloading assignment operator.问题是我的测试程序在重载赋值运算符后没有输出任何内容。

For my assignment operator, I use a Clear() function to clear the list entirely before the copy.对于我的赋值运算符,我使用Clear()函数在复制之前完全清除列表。 I put it in the destructor and checked that it works fine.我把它放在析构函数中并检查它是否工作正常。 I also checked my copy constructor and it worked fine as well.我还检查了我的复制构造函数,它也运行良好。

File node.h : defines the node building block文件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;
    }
};

File list.h : defines the linked list template文件list.h :定义链表模板

#include "node.h"

template <class T>
class List {
public:

    // default constructor
    List();

    // Destructor
    ~List();

    // Copy constructor
    List(const List<T> &copyThis);

    // 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;
};

This header also provides the implementation of these member functions:这个头文件还提供了这些成员函数的实现:

template <class T>
List<T>::List(){
    head = NULL;
}

template <class T>
List<T>::~List(){
    Clear();
}

template <class T>
List<T>::List(const List<T> &copyThis){
    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;
}

File main.cpp : tests the classes文件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;
}

The problem I currently have is the overloading assignment operator function.我目前遇到的问题是重载赋值运算符函数。 Below is when I copy the whole execution from the copy constructor function and it runs.下面是当我从复制构造函数复制整个执行并运行时。

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;
}

The output for this is:这个输出是:

2->3->|||

However, when I simplify the code like below, it doesn't output anything:但是,当我像下面这样简化代码时,它不会输出任何内容:

template <class T>
    List<T>& List<T>::operator =(const List<T>& RHS){
        if (this != &RHS) {
            this->Clear();
            *this = List<T>(RHS); 

        }
        return *this;
    }

Can anyone tell me why it doesn't work and how to simplify it efficiently?谁能告诉我为什么它不起作用以及如何有效地简化它? I really appreciate it.对此,我真的非常感激。

The problem问题

The assignment operator stops everything because of a stack overflow.由于堆栈溢出,赋值运算符停止了所有操作。

In fact, your implementation of the assignment operator uses itself the assignment operator, so that it calls itself recursively until the stack is exhausted:事实上,赋值运算符的实现使用了赋值运算符,因此它会递归调用自己,直到堆栈耗尽:

    *this       =    List<T>(RHS);  // OUCH !!
      |         |          |
      V         V          V
    <ListT> operator=   List<T>   ==> cals operator= again !!

The solution解决方案

  1. Rewrite the operator so that it doesn't call itself.重写运算符,使其不调用自身。
  2. Possibly clone every node, so to avoid that 2 lists share the same node and tha the first one that frees its node causes dangling pointers and UB for the other.可能克隆每个节点,以避免 2 个列表共享同一个节点,而第一个释放其节点的列表会导致悬空指针和 UB 为另一个。
  3. Not related, but please avoid using namespaces in headers.不相关,但请避免在标题中使用命名空间。 This is an extremely bad habit for later.这是一个极坏的习惯,以备后用。

Additional tip : This article recommends some good and elegant practices for operator overloading.附加提示本文为运算符重载推荐了一些好的和优雅的做法。 For the assignment operator, it suggests to use the copy constructor (as you attempt to do) but instead of assigning (your problem), swapping (to be verified, but swapping the heads in your case would certainly do the trick).对于赋值运算符,它建议使用复制构造函数(正如您尝试做的那样),而不是分配(您的问题),而是交换(有待验证,但在您的情况下交换头肯定会成功)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM