我有以下单链表实施。
template <typename T> struct node{
node(T data):data(data),next(nullptr){}
T data;
node<T> * next;
};
template< typename T> class slist{
node<T>* head;
int size;
public:
slist(node<T>* head):head(head), size(0){}
slist(const slist<T>& rhs){
node<T>* temp = rhs.getHead();
node<T>* p = new node<T>(temp->data);
head = p;
node<T>* current = p;
while(temp != nullptr){
current = current->next;
current->data = temp->data;
}
}
~slist(){
if(head == nullptr) return;
while(head != nullptr){
node<T>* current = head;
head = head->next;
delete(current);
}
}
slist& operator= (const slist& rhs){
}
node<T>* getHead()const {
return head;
}
void insertFront(T item){
node<T>* p = new node<T>(item);
if(head == nullptr){
p = head;
size++;
return;
}
p->next = head;
head = p;
size++;
}
void insertBack(T item){
node<T>* p = new node<T>(item);
node<T>* current = head;
while(current->next != nullptr){
current = current->next;
}
current->next = p;
size++;
}
void remove(T item){
bool check = false;
node<T>* current = head;
try {
while(current != nullptr){
if(current->data == item) check = true;
current = current->next;
}
if(!check){
throw std::runtime_error("Item not in list");
}
}catch(std::runtime_error& e){
std::cout<<e.what()<<std::endl;
exit(-1);
}
current = head;
while(current != nullptr){
if(current->next->data == item){
node<T>* temp = current->next;
current->next = current->next->next;
delete(temp);
break;
}
current = current->next;
}
size--;
}
int getSize () const {
return size;
}
void printList(){
node<T>* current = head;
while(current != nullptr){
if(current->next != nullptr){
std::cout<<current->data<<"->";
}else{
std::cout<<current->data<<std::endl;
}
current = current->next;
}
}
};
根据类的当前实现和复制构造函数,有人可以帮助赋值运算符重载。另外,我对复制构造函数和赋值重载有点困惑。我的理解是复制构造函数创建一个新列表,它与旧列表中的旧列表具有相同的值。这个所有节点的下一个地址将是不同的,但值是相同的,因为它是一个深拷贝。我的理解是正确的,然后是分配重载的内容吗?
答案 0 :(得分:5)
如果您已经有了复制构造函数和析构函数,那么还要实现swap()
,然后根据这三个来实现您的复制赋值运算符,例如:
template <typename T>
slist<T>& slist<T>::operator= (slist<T> other) {
this->swap(other);
return *this;
}
请注意,参数很容易被复制:与复制构造函数不同,复制赋值可以通过值获取其参数。
关于语义:
复制构造函数创建一个与原始对象具有相同值的新对象,例如:
slist<int> sl1;
// insert elements into sl1
slist<int> sl2(sl1); // uses the copy constructor
复制赋值将现有对象的值替换为赋值的值,例如
slist<int> sl1;
slist<int> sl2;
// possibly modify both sl1 and sl2
sl2 = sl1; // uses the copy assignment operator
答案 1 :(得分:1)
您需要考虑以下情况:
slist<int> newone = other;
slist<int> a; /* ... */ a = other;
现在,这两项操作 - 顾名思义 - 都是原始数据结构的副本。究竟是什么意思取决于你想要如何实现它,但以下应该 - 保持接近原则的最小意外 - 持有:
slist<int> a = some_generator(), b = another_generator();
slist<int> c = a;
// a == c should be true
b = a;
// a == b should be true now
modify(a);
// a == b should be false now, BUT b should be in the same state as before!
实现这一目标的最简单方法是制作 - 正如您已经建议的那样 - 深层拷贝。因此,您基本上与复制构造函数中的相同。您可以复制每个节点,使它们与原始节点具有相同的值,但它们是不同的实体。
如果你的目标也是“现代C ++”,那就是C ++ 11,那么你还有一个移动构造函数和一个移动赋值运算符可能想要实施。
如评论中所述,您的深层复制算法不正确:您需要复制每个节点:
// if in assigment, delete the nodes pointed to by head first!
node<T> const * iterator = other.getHead();
if (iterator != nullptr) { // in your implementation, head could be a nullptr
node<T> * new_node = new node<T>(*iterator); // make a copy of head
head = new_node;
while (iterator->next) {
iterator = iterator->next;
node<T> * copy = new node<T>(*iterator);
new_node->next = copy;
new_node = copy;
}
new_node->next = nullptr;
}
此外,如果可以的话,更喜欢智能指针,在这种情况下,unique_ptr
而不是原始指针。