我是C ++的新手,因此这个问题。我在C ++中有一个单一链接列表的玩具实现。
template<typename T>
class List {
template<typename U>
struct Node {
U data_;
Node<U>* next_;
Node() : data_(0), next_(nullptr) {}
Node(U data) : data_(data), next_(nullptr) {}
};
private:
Node<T>* head_;
std::size_t size_;
public:
List() : head_{nullptr}, size_{0} {}
void insert(const T& item) {
Node<T>* p(new Node<T>(item));
if (size_ == 0) {
head_ = p;
} else {
p->next_ = head_;
head_ = p;
}
size_++;
}
std::size_t getSize() {
return size_;
}
~List(){
while(head_){
Node<T> p = head_;
delete(p);
head_ = head_->next_;
}
};
这段代码似乎有效。但问题是new
分配的对象永远不会被清除,尽管有~List()
析构函数。有人可以帮助我理解,我怎么能为这个类编写一个析构函数来清理所有分配的节点?
重要说明:我知道这可以使用智能指针来完成,但我想了解旧学校管理堆栈的方法。
while(head_){
Node<T> p = head_; <-- change to pointer
delete(p); <-- you can't delete this right now
head_ = head_->next_;
}
p
应该是一个指针。你不能马上删除p
。你必须找到next
节点,然后删除p
。也使用delete p;
而不是delete (p);
如下:
~List() {
while(head_) {
Node<T> *p = head_;
head_ = head_->next_;
delete p;
}
}
如评论中所述,Node
不需要是模板。你可以简化你的课程。 insert
也可以简化,因为head_
初始化为nullptr
,你可以安全地分配p->next_ = head_;
template<typename T> class List {
struct Node {
T data_;
Node* next_;
Node() : data_(0), next_(nullptr) {}
Node(T data) : data_(data), next_(nullptr) {}
};
Node* head_;
std::size_t size_;
public:
List() : head_{ nullptr }, size_{ 0 } {}
void insert(const T& item) {
Node* p = new Node(item);
p->next_ = head_;
head_ = p;
size_++;
}
std::size_t getSize() {
return size_;
}
~List() {
while(head_) {
Node *marked = head_;
head_ = head_->next_;
delete marked;
}
}
};
一般的想法是你必须弄清楚谁是对象的所有者,以决定谁应该删除它。
对于节点,List是所有者。因此,您应该以一种方式仔细开发所有方法,一旦List失去对象的所有权,它就会确保删除对象或接管所有权。
想要释放内存的明显地方是,首先删除列表。其次,当你删除一个元素时,例如弹出它。
让我们看看两种情况。
首先删除列表。为此你需要编写一个析构函数,它遍历列表并逐个删除元素。为此我指的是@ barmak-shemiani的答案。
对于弹出元素的情况,您可以执行以下操作:
T pop() {
Node<T> *tmp = head_;
if (head_ != nullptr)
head_ = head_->next_;
T data = tmp->data_;
delete tmp;
return data;
}