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



我一直在让双链表的赋值运算符正常工作时遇到问题。当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;
};

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

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

您也有一个小的内存泄漏,因为您正在为forward变量分配一个新的Node,然后如果源列表不为空,则立即重新分配forward以指向另一个Node。您永远不会delete您使用new分配的Node。在清除现有节点时,不应该分配任何东西。

为了更安全一点,您应该将列表的清除封装在一个单独的方法中,然后您可以在需要时调用该方法(不要忘记在析构函数中,而不仅仅是在赋值operator=中(。

如果您使用复制和交换习惯用法在复制构造函数(您确实有一个,对吧?(方面实现您的赋值operator=,那就更好了。既然您显然使用的是C++11或更高版本,那么您也应该实现一个move构造函数。这些步骤将极大地简化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) {}
};

void LinkedList::insertToFront(const ItemType& val) 
{
Node* temp = new Node(val);
if (!tail)
tail = temp; // make new node tail if list is empty
if (head)
{
temp->next = head; // point current head towards temp
head->prev = temp;
}
head = temp;
}
void LinkedList::addToEnd(const ItemType& val) 
{
Node* temp = new Node(val);
if (!head)
head = temp; // make new node head if list is empty
if (tail)
{
temp->prev = tail; // point current tail towards temp
tail->next = temp;
}
tail = temp;
}

相关内容

  • 没有找到相关文章

最新更新