C ++中List类的析构函数

时间:2017-12-30 17:02:20

标签: c++ memory-management containers singly-linked-list object-lifetime

我是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()析构函数。有人可以帮助我理解,我如何为这个类编写析构函数来清理所有已分配的节点?

重要提示:我知道这可以使用智能指针来完成,但我想了解旧学校管理堆的方式。

2 个答案:

答案 0 :(得分:7)

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; } } };

grep -oP '\b[A-Z0-9_]+\b' file1.txt  

答案 1 :(得分:-1)

一般的想法是你必须找出对象的所有者,以决定谁应该删除它。

关于节点,List是所有者。因此,您应该仔细开发所有方法,一旦List失去对象的所有权,它就会确保删除对象或接管所有权。

当您要释放内存时,显而易见的地方是,首先删除列表。其次,当你删除一个元素时,例如弹出它。

让我们看看两种情况。

首先删除列表。为此你需要编写一个析构函数,它遍历列表并逐个删除元素。为此我指的是@ barmak-shemiani的答案。

对于弹出元素的情况,您可以执行以下操作:

  T pop() {
    Node<T> *tmp = head_;
    if (head_ != nullptr)
      head_ = head_->next_;
    T data = tmp->data_;
    delete tmp;
    return data;
  }