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

时间:2018-07-12 20:56:07

标签: c++ linked-list operator-overloading doubly-linked-list assignment-operator

我很难让我的赋值运算符使双向链接列表正常工作。当rhs是一个空列表时,该运算符可以正常工作,但是如果填充了该列表,它将无法正常工作,并会引发异常错误,提示“读取访问冲突”

这是我的主程序,将无法运行。

#include <cstdlib>

#include "linkedlist.h"

using namespace std;

int main()
{
    LinkedList e1;
    e1.insertToFront("A");
    e1.insertToFront("B");
    e1.insertToFront("C");

    LinkedList e2;

    e2.insertToFront("Please work");

    e1 = e2; //Expecting e1 to now just hold "Please work".

    system("pause");
}

这里是赋值运算符本身(在单独的头文件中)。

// assignment operator
const LinkedList& LinkedList::operator=(const LinkedList& rhs)
{
    Node* temp;
    temp = head;
    Node* forward;
    forward = new Node;

    while (temp != nullptr) // clear memory of target variable
    {
        forward = temp->next;
        delete temp;
        temp = forward;
    }

    if (rhs.head == nullptr)
    {
    head = nullptr;
    tail = nullptr;
    } 
      //GOOD THROUGH THIS PNT.

    else
    {       
        temp = rhs.head;

        while (temp != nullptr)
        {
            this->addToEnd(temp->value);
            temp = temp->next;
        }
    }

    return *this;
}

这是我调用的addToEnd函数以及Node结构。

void LinkedList::addToEnd(const ItemType& val) 
{
    Node* temp;
    temp = new Node;
    temp->value = val;

    if (this->head == nullptr)
    {
        head = temp; // make new node head if list is empty
        head->next = nullptr;
        head->prev = nullptr;
        tail = temp;
    }

    else
    {
        temp->prev = tail; // otherwise point current tail towards temp
        temp->next = nullptr;
        tail->next = temp;
        tail = temp;
    }

    return;
}

////////////////////////////////////////////////////////////////////////

struct Node
{
    ItemType value;
    Node* next;
    Node* prev;
};

2 个答案:

答案 0 :(得分:3)

您删除了旧节点,但是忽略了将headtail设置为nullptr,因此这些指针仍然指向已删除的对象。然后,您尝试将元素添加到该已删除列表中,并获得未定义行为。

答案 1 :(得分:0)

清除现有节点时,在开始从源列表中复制值之前,没有将headtail指针重置为nullptr。因此,您正在使用无效的指针将新的Node添加到列表中。

您还存在少量内存泄漏,因为您正在为Node变量分配一个新的forward,然后如果重新分配forward指向另一个Node,源列表不为空。您永远不会deleteNode分配的new。清除现有节点时,您不应分配任何资源。

为了使事情更安全,您应该将列表的清除内容包装在自己的单独方法中,然后可以在需要时调用该方法(不要忘了在析构函数中,而不仅仅是在赋值{ {1}}。

如果您使用copy-and-swap idiom就复制构造函数(您确实有一个,对吗?)实现分配operator=会更好。并且由于您显然使用的是C ++ 11或更高版本,因此还应该实现move构造函数。这些步骤将大大简化operator=的实现,并使其更安全地使用。

尝试一下:

operator=

class LinkedList
{
public:
    LinkedList() = default;
    LinkedList(const LinkedList& src);
    LinkedList(LinkedList&& src);
    ~LinkedList();
    ...
    LinkedList& operator=(LinkedList rhs);
    ...
private:
    Node *head = nullptr;
    Node *tail = nullptr;
    ...
};

您还可以稍微简化#include <utility> LinkedList::LinkedList(const LinkedList& src) { Node* temp = src.head; while (temp) { addToEnd(temp->value); temp = temp->next; } } LinkedList::LinkedList(LinkedList&& src) : head(src.head), tail(src.tail) { src.head = src.tail = nullptr; } LinkedList::~LinkedList() { clear(); } void LinkedList::clear() { Node *temp = head; head = tail = nullptr; while (temp) { Node *forward = temp->next; delete temp; temp = forward; } } LinkedList& LinkedList::operator=(LinkedList rhs) { std::swap(head, rhs.head); std::swap(tail, rhs.tail); return *this; } insertToFront()方法:

addToEnd()

struct Node
{
    ItemType value;
    Node* next = nullptr;
    Node* prev = nullptr;

    Node(const ItemType& val) : value(val) {}
};
相关问题