我正在努力学习C++,但有一点困惑。
我从告诉的文本告诉我,如果我想删除const T&
类型的节点,我应该首先创建该节点类型的新指针,然后使用内置的C++delete[]
将其删除。但是,如果我只是设置了从要删除节点的上一个元素到要删除节点下一个元素的链接,会发生什么?类似于:
*p = node.previous;
p-> next = node.next;
或者这会导致内存泄漏?
我很困惑,因为我在其他地方读过,永远不会随意删除指针,但我正在使用的示例代码有一些类似的内容:
Node<T> *p = node-to-be-deleted;
delete p;
删除节点的最佳方式是什么?
假设您的节点如下所示:
struct Node
{
Node* previous;
Node* next;
SomeType data;
};
然后:
*p = node.previous;
p-> next = node.next;
然后是。这将导致内存泄漏
它还使p->next->prev
指向错误的节点。
我很困惑,因为我在其他地方读过,永远不会随意删除指针,但我正在使用的示例代码有一些类似的内容:
是的,最好的方法是"永远不要删除指针"。但这必须与一些背景相适应。您不应该手动删除指针,因为指针应该由控制其寿命的对象管理。这些对象中最简单的是智能指针或容器。但对于这种情况,这将是过分的(因为您正在创建容器(。
在创建容器(列表(时,您需要自己进行管理(注意C++已经有两个丢失的类型std::list用于类型t的值列表,boost::ptr_list用于指向t的指针列表(。但这是一个很好的锻炼尝试和做自己。
以下是一个初学者列出清单及其生成的注释的代码审查示例:
http://codereview.stackexchange.com:C++中的链表
我希望这有助于解释如何创建和删除对象。
Node* p = new Node; // This is how you allocate a node
delete p; // This is how you delete it
delete[]运算符应用于动态分配的数组:
Node* nodelist = new Node[ 4 ]; // nodelist is now a (dynamically allocated) array with 4 items.
delete[] nodelist; // Will delete all 4 elements (which is actually just one chunk of memory)
只有当Node
实现析构函数来更新周围Node
实例的previous
和next
指针时,直接删除Node
才有意义,例如:
Node::~Node()
{
if (previous) previous->next = next;
if (next) next->previous = previous;
}
Node *p = node-to-be-deleted;
delete p;
否则,在删除有问题的Node
之前,您必须更新Node
指针,例如:
Node *p = node-to-be-deleted;
if (p->previous) p->previous->next = p->next;
if (p->next) p->next->previous = p->previous;
delete p;
话虽如此,最好的方法是从一开始就不手动实现链表。在C++中,使用std::list
容器,并让它为您处理这些细节。
void deleteNode( Node * p )
{
Node * temp = p->next;
p->data = p->next->data;
p->next = temp->next;
free(temp);
}
这是我几个月前做的事。
template <class T>
T LinkedList<T>::remove(int pos)
{
if (pos < 1 || pos > size)
{
throw pos;
}
ListNode * temp;
if (pos == 1)
{
temp=head;
head = head->next;
}
else
{
int i=1;
ListNode * prev = head;
while(i<pos-1)
{
i++;
prev=prev->next;
}
temp = prev->next;
prev->next = (prev->next)->next;
}
--size;
return temp->item;
}