C++ 中列表 class 的析构函数
Destructor for a List class in C++
我是 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_;
}
};
此代码似乎有效。尽管有 ~List()
析构函数,但问题是 new
分配的对象永远不会被清理。有人可以帮助我理解,我如何为这个 class 编写一个析构函数来清理所有分配的节点?[=14=]
重要说明:我知道这可以使用智能指针来完成,但我想了解管理堆的老派方法。
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
不需要是模板。您可以简化您的 class。 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;
}
}
};
一般的想法是,您必须弄清楚谁是对象的所有者,才能决定谁应该删除它。
相对于节点,列表是所有者。所以你应该仔细开发所有的方法,一旦列表失去对象的所有权,它确保对象被删除或所有权被接管。
当你想释放内存时,显而易见的地方是,第一个你删除列表。其次,当你删除一个元素时,例如弹出它。
让我们看看这两种情况。
首先删除列表。为此,您需要编写一个析构函数,它遍历列表并一个接一个地删除元素。为此,我参考了@barmak-shemiani 的回答。
对于弹出元素的情况,您可以执行以下操作:
T pop() {
Node<T> *tmp = head_;
if (head_ != nullptr) {
head_ = head_->next_;
T data = tmp->data_;
delete tmp;
return data;
}
throw std::runtime_error("Can't pop an empty list")
}
我是 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_;
}
};
此代码似乎有效。尽管有 ~List()
析构函数,但问题是 new
分配的对象永远不会被清理。有人可以帮助我理解,我如何为这个 class 编写一个析构函数来清理所有分配的节点?[=14=]
重要说明:我知道这可以使用智能指针来完成,但我想了解管理堆的老派方法。
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
不需要是模板。您可以简化您的 class。 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;
}
}
};
一般的想法是,您必须弄清楚谁是对象的所有者,才能决定谁应该删除它。
相对于节点,列表是所有者。所以你应该仔细开发所有的方法,一旦列表失去对象的所有权,它确保对象被删除或所有权被接管。
当你想释放内存时,显而易见的地方是,第一个你删除列表。其次,当你删除一个元素时,例如弹出它。
让我们看看这两种情况。
首先删除列表。为此,您需要编写一个析构函数,它遍历列表并一个接一个地删除元素。为此,我参考了@barmak-shemiani 的回答。
对于弹出元素的情况,您可以执行以下操作:
T pop() {
Node<T> *tmp = head_;
if (head_ != nullptr) {
head_ = head_->next_;
T data = tmp->data_;
delete tmp;
return data;
}
throw std::runtime_error("Can't pop an empty list")
}