我在C ++中尝试在链表中重载=运算符,并编写了下面的代码。
template<class T>
class List {
public:
List();
List (T t_data);
List& operator=(const List<T> &L);
private:
template<class L>
class Node {
public:
L data;
Node *next;
Node *prev;
Node(T t_data) {
data = t_data;
next = prev = NULL;
}
};
Node<T> *head;
};
template<class T>
List& List<T>::operator=(const List<T> &L) {
Node<T> *t_head = head;
Node<T> *t_tail = head->prev;
Node<T> *temp;
while(t_head ! = t_tail) {
temp = t_head;
t_head = t_next;
delete temp;
}
head = L.head;
t_head = t_tail = temp = NULL;
return *this;
}
我编写这段代码只是为了练习模板,指针和运算符重载,但我想知道在这种情况下=运算符的意义。即使我像
一样使用它List L1(2);
List L2(3);
L1 = L2;
现在L1中反映的任何变化都会反映在L2中,所以我们可以做到
List L1(2);
List *L2 = &L1;
这也将解决上述目的。那么为什么链接列表的=运算符会在许多文章和书籍中重载?
编辑:@ T.C。在参考您的注释时,如果我不将Node
声明为模板,则代码将如下所示
class List {
public:
List();
List (T t_data);
List& operator=(const List<T> &L);
private:
class Node {
public:
T data;
Node *next;
Node *prev;
Node(T t_data) {
data = t_data;
next = prev = NULL;
}
};
Node *head;
};
现在,如果我在如下面的成员函数中声明Node的对象
void List::func() {
Node temp;
…..
}
然后如何解决这个“临时”对象的数据成员“数据”的类型是什么。请告诉我。
答案 0 :(得分:5)
在C ++中,通常的做法是拥有价值语义,即在L1 = L2;
之后,对L1
的更改 <{1}},并且反之亦然。
因此,L2
的实施是错误的。它应该做的是:
一个常见的习语是copy and swap成语:你创建另一个链表的临时副本(第1点),用临时副本交换当前链表的内容(第3点),当你的赋值函数返回时,临时副本将与分配给(第2点)的链接列表的前一内容一起销毁。
你能用不同的方式吗?当然,但它(1)是非常单一的,(2)需要远远超过你现在正确做的。例如,当operator =
和operator =
的析构函数在分配后运行时,您当前的L1
实现将导致双重删除。您需要在析构函数中使用某种引用计数和其他逻辑,以确保您不会删除仍在使用的L2
,但也不会泄漏内存。< / p>
旁注:Node
不应该是模板,因为它永远不应存储Node
以外的其他内容。