![](/img/trans.png)
[英]Assignment Operator for singly linked list with dynamic allocation in C++ (MS Visual Studio 2015)
[英]Singly linked list assignment operator overload in C++
我有以下單鏈接列表實現。
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;
}
}
};
基於類和副本構造函數的當前實現,有人可以幫助分配運算符重載。 我對復制構造函數和賦值重載也有些困惑。 我了解的是,復制構造函數會創建一個新列表,該列表的值與舊列表中的舊列表相同。 所有節點的下一個地址將有所不同,但由於是深度復制,因此值將相同。 我的理解是正確的,然后分配超負荷做什么?
如果您已經具有復制構造函數和析構函數,則還應實現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
您需要考慮以下情況:
slist<int> newone = other;
slist<int> a; /* ... */ a = 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及更高版本),那么您可能想要實現一個move構造函數和一個move賦值運算符 。
如評論中所述,您的深層復制算法不正確:您需要制作每個節點的副本:
// 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
,而不是原始指針。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.