我在我的鏈表實作方面遇到了問題,我正在嘗試創建一個復制建構式。
// Copy Constructor
List342(const List342& source)
{
*this = source;
}
List342& operator=(const List342& source)
{
Node<T>* s_node = nullptr; // Source node
Node<T>* d_node = nullptr; // Destination node
if (this == &source)
{
return *this;
}
// Empty memory on destination
DeleteList();
// If the source is empty, return the current object.
if (source.head_ == nullptr)
{
return *this;
}
// Copy source node to destination node, then make destination node the head.
d_node = new Node<T>;
d_node->data = (source.head_)->data;
head_ = d_node;
s_node = (source.head_)->next;
// Loop and copy the nodes from source
while (s_node != nullptr)
{
d_node->next = new Node<T>;
d_node = d_node-> next;
d_node->data = s_node->data;
s_node = s_node->next;
}
return *this;
}
出于某種原因,d_node->data = s_node->data盡管while回圈試圖阻止這種情況發生,VS Studio 還是在線上向我拋出了讀取訪問沖突。
罪魁禍首可能在于DeleteList,但出于某種原因,我的其他方法(例如列印鏈表)在呼叫 后沒有問題DeleteList,因為它什么也不列印。我只是想知道這種DeleteList方法是否有任何缺陷。
// Delete all elements in the linked list
// Not only do you need to delete your nodes,
// But because the Node data is a pointer, this must be deleted too
void DeleteList()
{
// Similar to the linkedlist stack pop method except you're running a while
// loop until you the is empty.
Node<T>* temp;
while (head_ != nullptr)
{
temp = head_;
head_ = head_->next;
// For some reason if I try to delete temp->data, I keep getting symbols not loaded or debug
// assertion errors
// delete temp->data;
// What I can do here is set it to null
// Then delete it. This may have to do how uninitialized variables have random memory assigned
temp->data = nullptr;
delete temp->data;
delete temp;
}
}
這是Node定義:
template <class T>
struct Node
{
T* data;
//string* data;
Node* next;
}
uj5u.com熱心網友回復:
通過Node::data宣告為指標,您的代碼負責遵循3/5/0 規則來data正確管理指標。但它并沒有這樣做。您的復制賦值運算子是淺復制指標本身,而不是深復制它們指向的物件。
因此,陳述句會DeleteList()崩潰delete temp->data;,因為您最終會有多個Nodes 指向記憶體中的相同物件,從而破壞了獨特的所有權語意。當一個Node被銷毀,洗掉它的data物件時,Node從它復制的任何其他物件現在都會留下一個指向無效記憶體的懸空指標。
如果您必須使用指標 for Node::data,那么您需要data單獨使用復制構造每個物件,new以便DeleteList()以后可以單獨使用delete它們,例如:
d_node = new Node<T>;
d_node->data = new T(*(source.head_->data)); // <--
...
d_node->next = new Node<T>;
d_node = d_node->next;
d_node->data = new T(*(s_node->data)); // <--
...
但是,如果您一開始就簡單地 make Node::datanot be 指標,則不再需要這樣做:
template <class T>
struct Node
{
T data; //string data;
Node* next;
}
話雖如此,您的復制建構式正在呼叫您的復制賦值運算子,但該head_成員尚未初始化(除非它已初始化并且您只是沒有顯示)。呼叫DeleteList()無效串列是未定義行為。使用復制建構式(所謂的copy-swap idiom)實作賦值運算子會更安全,而不是相反,例如:
// Copy Constructor
List342(const List342& source)
: head_(nullptr)
{
Node<T>* s_node = source.head_;
Node<T>** d_node = &head_;
while (s_node)
{
*d_node = new Node<T>;
(*d_node)->data = new T(*(s_node->data));
// or: (*d_node)->data = s_node->data;
// if data is not a pointer anymore...
s_node = s_node->next;
d_node = &((*d_node)->next);
}
}
List342& operator=(const List342& source)
{
if (this != &source)
{
List342 temp(source);
std::swap(head_, temp.head_);
}
return *this;
}
但是,如果您確保在呼叫之前初始化為,您所展示的復制建構式可以安全地作業,例如:head_nullptroperator=
// Copy Constructor
List342(const List342& source)
: head_(nullptr) // <--
{
*this = source;
}
或者:
// Default Constructor
List342()
: head_(nullptr) // <--
{
}
// Copy Constructor
List342(const List342& source)
: List342() // <--
{
*this = source;
}
或者,head_直接在類宣告中初始化,根本不在建構式中:
template<typename T>
class List342
{
...
private:
Node<T> *head_ = nullptr; // <--
...
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/360379.html
