我很难让我的赋值运算符使双向链接列表正常工作。当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;
};
答案 0 :(得分:3)
您删除了旧节点,但是忽略了将head
和tail
设置为nullptr
,因此这些指针仍然指向已删除的对象。然后,您尝试将元素添加到该已删除列表中,并获得未定义行为。
答案 1 :(得分:0)
清除现有节点时,在开始从源列表中复制值之前,没有将head
和tail
指针重置为nullptr
。因此,您正在使用无效的指针将新的Node
添加到列表中。
您还存在少量内存泄漏,因为您正在为Node
变量分配一个新的forward
,然后如果重新分配forward
指向另一个Node
,源列表不为空。您永远不会delete
用Node
分配的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) {}
};