链表C++中的赋值运算符

Assignment operator in linked list C++

本文关键字:赋值运算符 C++ 链表      更新时间:2023-10-16

我正在尝试在c ++中实现链表。

我像这样实现我的赋值运算符:

// assignment operator
template<class T>
LinkedList<T>& LinkedList<T>::operator = (const LinkedList& rhs) {
if (&rhs != this) {
    Node *tmp = head;
    while (tmp -> next) {
        head = head -> next;
        delete tmp;
        tmp = head;
    }
    tmp = rhs -> head;
    while (tmp) {
        append(tmp);
        tmp = tmp -> next;
    }
}
    return *this;
}

在我的主函数中,我使用以下代码进行测试:

LinkedList<int> *lst1 = new LinkedList<int>(7);
LinkedList<int> *lst2 = new LinkedList<int>(101);
std::cout << lst1 -> head -> data << std::endl;
std::cout << lst2 -> head -> data << std::endl;
lst1 = lst2;
std::cout << lst1 -> head -> data << std::endl;
delete lst1;
delete lst2;            <--------------- error here

正如我所料,控制台输出:

7 101

101

但是当程序尝试删除lst2时,我收到一条错误消息:

未分配正在释放的指针

我使用调试器并找出程序何时执行分配:

lst1 = lst2;
lst1 实际上指的是指向 lst2 而不是获取 lst2

副本的地址,因此当我删除 lst1 时,lst2 已经消失了。

那么谁能告诉我我的分配运算符出了什么问题?

如果这是一个新手问题,我很抱歉,但我已经花了几个小时,无法弄清楚。

我完成的代码如下所示:

template<class T>
class LinkedList {
private:
    class Node {
    public:
        T data;
        Node *next;
        // default constructor
        Node() = default;
        // constructor with data
        Node(const T& data) : data(data), next(NULL) {}
    };
public:
    Node *head;
    LinkedList(const LinkedList& copyLst);
    LinkedList& operator=(const LinkedList& byValList);
    LinkedList() : head(NULL){}
    LinkedList(Node *newNode) : head(newNode) {}
    LinkedList(T val) {
        head = new Node(val);
    }
    ~LinkedList();
    static LinkedList<int> sumLists(const LinkedList<int>& lst1, const LinkedList<int>& lst2) ;
    void insertAtFront(T val);
    void insertAtEnd(T val);
    void printList();
    void insert(T val);
    void append(const Node&);
};
// copy constructor
template<class T>
LinkedList<T>::LinkedList(const LinkedList<T>& copyLst) {
    const Node *cpCurrent = copyLst.head;
    Node *lsCurrent = NULL;
    if (cpCurrent != NULL) {
        head = new Node(cpCurrent -> data);
        lsCurrent = head;
        cpCurrent = cpCurrent -> next;
    }
    while (cpCurrent != NULL) {
        Node *newNode = new Node(cpCurrent -> data);
        lsCurrent -> next = newNode;
        lsCurrent = lsCurrent -> next;
        cpCurrent = cpCurrent -> next;
    }
}
// assignment operator
template<class T>
LinkedList<T>& LinkedList<T>::operator = (const LinkedList& rhs) {
    if (&rhs != this) {
        Node *tmp = head;
        while (tmp -> next) {
            head = head -> next;
            delete tmp;
            tmp = head;
        }
        tmp = rhs -> head;
        while (tmp) {
            append(tmp);
            tmp = tmp -> next;
        }
    }
    return *this;
}
// destructor
template<class T>
LinkedList<T>::~LinkedList() {
    Node *current = head;
    while (current != NULL) {
        head = head -> next;
        delete current;
        current = head;
    }
}
template<typename T>
void LinkedList<T>::append(const Node& node ){
    if (NULL == head) {
        Node *newNode = new Node(node -> data);
        head = newNode;
    } else {
        Node *current = head;
        while (current -> next) {
            current = current -> next;
        }

        Node *newNode = new Node(node -> data);
        current -> next = newNode;
    }
}

您当前的实现复制了复制构造函数中已经存在的代码,那么为什么不重用它呢?

如果你有一个工作的副本构造函数和析构函数,使用复制/交换习惯用法将是实现赋值运算符的最简单、最安全的方法。

#include <algorithm>
//...
template<class T>
LinkedList<T>& LinkedList<T>::operator = (const LinkedList<T>& rhs) 
{
    LinkedList<T> temp(rhs);
    std::swap(temp.head, head);
    return *this;
}

假设复制构造函数和析构函数正常工作,则可以保证正常工作。 我们创建对象rhs的副本temp,并将其内容与*this的内容交换。 当temp在返回时被销毁时,它会带走曾经在*this中的旧数据。

如果您有 C++ 11 编译器,则可以利用按值传递的传入参数的移动构造。

#include <algorithm>
//...
template<class T>
LinkedList<T>& LinkedList<T>::operator = (LinkedList<T> rhs) 
{
    std::swap(rhs.head, head);
    return *this;
}
* 需要

注意的是,在使用 copy and swap 习语时,需要交换类的所有成员,否则可能会使类成员的不变量无效 *