删除指针时出现分段错误(核心已转储)
Segmentation fault (core dumped) when I delete pointer
我试图从链表中删除重复项,遇到了一个问题,这个问题可能很明显也很简单,但我已经很多年没用过 C++
了,我找不到我想要的通过阅读关于 SO 的类似问题,我做错了。
以下是我的部分代码。我删除了不相关的部分(例如构造函数、其他方法等)。
template<class T>
class Node {
Node() : data(NULL), next(NULL), prev(NULL) {}
explicit Node(T d) : data(d), next(NULL), prev(NULL) {}
explicit Node(T d, Node<T> *nxt, Node<T> *prv) : data(d), next(nxt), prev(prv) {}
~Node() { delete next; delete prev; }
T data;
Node *next;
Node *prev;
};
template<class T>
class LinkedList {
LinkedList() : head(NULL) {}
explicit LinkedList(Node<T> *head_node) : head(head_node) {}
LinkedList& operator=(const LinkedList ©_list);
~LinkedList(); //didn't implement this but I guess delete head is all?
Node<T>* head;
};
template<class T>
LinkedList<T> RemoveDuplicates(const LinkedList<T> &linked_list) {
//my = overload creates a whole new list with the same data as the original one
LinkedList<T> result = linked_list;
Node<T> *cur = result.head;
Node<T> *prev = NULL;
while (cur) {
if (...) { //duplicate found
Node<T> *temp = cur;
prev->next = cur->next;
cur = cur->next;
cur->prev = prev;
free(temp); //Here is my problem!!!
}
else {
prev = cur;
cur = cur->next;
}
}
return result;
}
首先,我做了 delete temp
,然后我得到了 Segmentation fault
。然后我意识到你只是delete
你new
。很公平,但是在 main
:
中构建整个列表时,我 new
每个 Node
Node<char> *h = new Node<char>('H'); //I have a constructor to handle this
Node<char> *e = new Node<char>('E');
Node<char> *l1 = new Node<char>('L');
Node<char> *l2 = new Node<char>('L');
Node<char> *o = new Node<char>('O');
h->next = e;
h->prev = NULL;
e->next = l1;
e->prev = h;
//and so on
那么,为什么我不能 delete
在其他地方 new
编辑过的东西?是因为 new
ed 超出了当前范围吗?
其次,free
space 工作正常,但显然不是正确的做法,因为我没有 malloc
但 new
ed!
我做错了什么?如何正确杀死那个删除的节点?[=26=]
Edit1:根据对我 post 的回复使其更具描述性
Edit2:添加了 3 种方法的规则
如果您使用 new
分配内存,则不能使用 free()
您可以将 malloc()
与 free()
一起使用,或将 new
与 delete
一起使用。您也不应该将 malloc()
和 free()
与对象一起使用,因为它们不像 new
和 delete
那样调用对象的构造函数和析构函数
因此,由于您使用 new
分配了节点,我们可以更改
free(temp); //Here is my problem!!!
到
delete temp;
在这种情况下,拥有构造函数和析构函数的代码非常重要。
默认情况下,您应该在构造函数中使用 "new",在析构函数中使用 "delete"。更具体地说,在构造函数中分配你需要的所有资源并在析构函数中释放是非常重要的,这样你就可以确保你没有任何内存泄漏。
free(temp);//You don't need this, also you don't need delete.
请post你的构造函数和析构函数代码。
L.E:
我认为你应该这样做:
template<class T>
class LinkedList
{
private:
struct Node {
T m_data;
Node *m_next;
Node *m_prev;
};
Node* m_first;
Node* m_last;
int m_count;
public:
LinkedList();
~LinkedList();
T GetFirst();
T GetLast();
void AddNode(T node);
void RemoveAt(int index);
T GetAt(int index);
int Count();
};
//constructor
template <typename T>
LinkedList<T>::LinkedList(){
m_count = -1;//-1 == "The list is empty!
}
template <typename T>
void LinkedList<T>::AddNode(T data){
Node* temp = new Node; //new is called only here -> delete is called in destructor or in RemoveAt
temp->m_data = data;
if (m_count > -1){//If the list contains one or more items
temp->m_next = m_first;
temp->m_prev = m_last;
m_last->m_next = temp;
m_last = temp;
m_count++;
}
else if (m_count == -1)
{//If no items are present in the list
m_first = temp;
m_first->m_next = temp;
m_first->m_prev = temp;
m_last = temp;
m_last->m_next = temp;
m_last->m_prev = temp;
m_count = 0;
}
}
template <typename T>
void LinkedList<T>::RemoveAt(int index){
if (index <= m_count)//verify this request is valid
{
Node* temp = m_last;
for (int i = 0; i <= index; ++i){
temp = temp->m_next;
}
temp->m_prev->m_next = temp->m_next;
temp->m_next->m_prev = temp->m_prev;
delete temp;
m_count--;
}
}
template <typename T>
T LinkedList<T>::GetAt(int index)
{
Node* temp = m_first;
if (index <= m_count && index > -1){
int i = 0;
while(i < index){
temp = temp->m_next;
i++;
}
}
return temp->m_data;
}
template <typename T>
T LinkedList<T>::GetFirst() {
return m_first->data;
}
template <typename T>
T LinkedList<T>::GetLast(){
return m_last->data;
}
template <typename T>
int LinkedList<T>::Count(){
return m_count;
}
template <typename T>
LinkedList<T>::~LinkedList(){
while(m_count > -1){
Node* temp = m_first;
m_first = temp->m_next;
delete temp;//delete in destructor
m_count--;
}
}
So why I am not allowed to delete something that was newed somewhere
else? Is it because it was newed outside the current scope?
您可以 delete
在其他地方 new
编辑。只要您指向有效地址,这就不是问题。当您随后尝试使用指向现在 delete
ed 地址的指针之一时,就会出现段错误。
Second, freeing the space works fine, but I feel that's like cheating!
您应该只在使用 malloc
时使用 free
,在使用 new
时才使用 delete
。你应该永远不要把它们混在一起。另外,在你delete
之后,养成了给指针变量赋值NULL
的习惯。
Because I may need things to be done on my Node's destructor.
封装数据的class内部也应该做自己的内存管理。例如,LinkedList
应该管理节点的内存。
这意味着,如果您有类似 LinkedList<T>::add(Node<T> *data)
的东西,您应该考虑 LinkedList<T>::add(T data)
之类的东西;然后列表 class 本身负责处理节点。
否则,您 运行 冒着将 new
ed 节点发送到列表中的风险,然后列表 delete
在某些时候在内部,但在其他地方,列表的客户端仍然持有对现在无效节点的引用。当客户端尝试使用它时,砰!:再次出现段错误。
What am I doing wrong? How to properly kill that removed node?
除了混合 new
s 和 free
s 之外,段错误很可能是由无效的内存访问触发的,因此您应该找到不再指向有效的指针(即 un deleted
) 内存。
有很多答案说 new/delete
和 malloc()/free()
应该总是这样配对,但我觉得应该说 为什么 完全正确。
与您的初始化一样,
Node<char> *h = new Node<char>('H');
new
关键字 returns 一个完整类型的对象对象指针,在语句本身中定义,而 malloc()
只是分配给定的内存 space 而没有分配类型,所以 returns 一个 void*
。此外,new/delete
处理来自 Free Store 的内存,而 malloc()/free()
allocate/free 堆上的内存,尽管某些编译器可能会根据 malloc()/free
在某些方面实现 new/free
实例。
还有一些重要的是 new
和 delete
分别调用构造函数和析构函数,而 malloc()
和 free()
只是分配和释放堆内存,没有考虑内存本身的状态。
这是对正确识别和解决 OP 的直接问题的其他答案的附录。需要快速浏览一下以解释接下来会发生什么。
Node<T> *temp = cur;
prev->next = cur->next;
cur = cur->next;
cur->prev = prev;
此时temp还没有被清除,所以next和prev仍然指向过去围绕cur的两个节点,现在链接在一起。如果不是这样,这将导致严重的问题:
free(temp); //Here is my problem!!!
free
失败,因为temp指向的值是new分配的。 NathanOliver 的回答涵盖了这一点,但隐藏在下面的是
会发生什么
delete temp;
这将调用析构函数来像清理小对象一样进行清理。不幸的是,Node
析构函数看起来像这样:
~Node() { delete next; delete prev; }
temp->next
仍然指向一个活节点。 temp->prev
也是如此。
下一个和上一个得到 delete
d。它调用它们的析构函数,delete
调用它们接触的两个节点,并调用将破坏列表中所有节点的死亡风暴。
如果双删不先杀程序。每个链接节点将尝试 delete
刚刚 deleted
它们的节点。不好。
很有可能 Node
析构函数应该只照顾自己,而将其他 Node
的析构留给 LinkedList
class.
我试图从链表中删除重复项,遇到了一个问题,这个问题可能很明显也很简单,但我已经很多年没用过 C++
了,我找不到我想要的通过阅读关于 SO 的类似问题,我做错了。
以下是我的部分代码。我删除了不相关的部分(例如构造函数、其他方法等)。
template<class T>
class Node {
Node() : data(NULL), next(NULL), prev(NULL) {}
explicit Node(T d) : data(d), next(NULL), prev(NULL) {}
explicit Node(T d, Node<T> *nxt, Node<T> *prv) : data(d), next(nxt), prev(prv) {}
~Node() { delete next; delete prev; }
T data;
Node *next;
Node *prev;
};
template<class T>
class LinkedList {
LinkedList() : head(NULL) {}
explicit LinkedList(Node<T> *head_node) : head(head_node) {}
LinkedList& operator=(const LinkedList ©_list);
~LinkedList(); //didn't implement this but I guess delete head is all?
Node<T>* head;
};
template<class T>
LinkedList<T> RemoveDuplicates(const LinkedList<T> &linked_list) {
//my = overload creates a whole new list with the same data as the original one
LinkedList<T> result = linked_list;
Node<T> *cur = result.head;
Node<T> *prev = NULL;
while (cur) {
if (...) { //duplicate found
Node<T> *temp = cur;
prev->next = cur->next;
cur = cur->next;
cur->prev = prev;
free(temp); //Here is my problem!!!
}
else {
prev = cur;
cur = cur->next;
}
}
return result;
}
首先,我做了 delete temp
,然后我得到了 Segmentation fault
。然后我意识到你只是delete
你new
。很公平,但是在 main
:
new
每个 Node
Node<char> *h = new Node<char>('H'); //I have a constructor to handle this
Node<char> *e = new Node<char>('E');
Node<char> *l1 = new Node<char>('L');
Node<char> *l2 = new Node<char>('L');
Node<char> *o = new Node<char>('O');
h->next = e;
h->prev = NULL;
e->next = l1;
e->prev = h;
//and so on
那么,为什么我不能 delete
在其他地方 new
编辑过的东西?是因为 new
ed 超出了当前范围吗?
其次,free
space 工作正常,但显然不是正确的做法,因为我没有 malloc
但 new
ed!
我做错了什么?如何正确杀死那个删除的节点?[=26=]
Edit1:根据对我 post 的回复使其更具描述性 Edit2:添加了 3 种方法的规则
如果您使用 new
free()
您可以将 malloc()
与 free()
一起使用,或将 new
与 delete
一起使用。您也不应该将 malloc()
和 free()
与对象一起使用,因为它们不像 new
和 delete
因此,由于您使用 new
分配了节点,我们可以更改
free(temp); //Here is my problem!!!
到
delete temp;
在这种情况下,拥有构造函数和析构函数的代码非常重要。
默认情况下,您应该在构造函数中使用 "new",在析构函数中使用 "delete"。更具体地说,在构造函数中分配你需要的所有资源并在析构函数中释放是非常重要的,这样你就可以确保你没有任何内存泄漏。
free(temp);//You don't need this, also you don't need delete.
请post你的构造函数和析构函数代码。
L.E:
我认为你应该这样做:
template<class T>
class LinkedList
{
private:
struct Node {
T m_data;
Node *m_next;
Node *m_prev;
};
Node* m_first;
Node* m_last;
int m_count;
public:
LinkedList();
~LinkedList();
T GetFirst();
T GetLast();
void AddNode(T node);
void RemoveAt(int index);
T GetAt(int index);
int Count();
};
//constructor
template <typename T>
LinkedList<T>::LinkedList(){
m_count = -1;//-1 == "The list is empty!
}
template <typename T>
void LinkedList<T>::AddNode(T data){
Node* temp = new Node; //new is called only here -> delete is called in destructor or in RemoveAt
temp->m_data = data;
if (m_count > -1){//If the list contains one or more items
temp->m_next = m_first;
temp->m_prev = m_last;
m_last->m_next = temp;
m_last = temp;
m_count++;
}
else if (m_count == -1)
{//If no items are present in the list
m_first = temp;
m_first->m_next = temp;
m_first->m_prev = temp;
m_last = temp;
m_last->m_next = temp;
m_last->m_prev = temp;
m_count = 0;
}
}
template <typename T>
void LinkedList<T>::RemoveAt(int index){
if (index <= m_count)//verify this request is valid
{
Node* temp = m_last;
for (int i = 0; i <= index; ++i){
temp = temp->m_next;
}
temp->m_prev->m_next = temp->m_next;
temp->m_next->m_prev = temp->m_prev;
delete temp;
m_count--;
}
}
template <typename T>
T LinkedList<T>::GetAt(int index)
{
Node* temp = m_first;
if (index <= m_count && index > -1){
int i = 0;
while(i < index){
temp = temp->m_next;
i++;
}
}
return temp->m_data;
}
template <typename T>
T LinkedList<T>::GetFirst() {
return m_first->data;
}
template <typename T>
T LinkedList<T>::GetLast(){
return m_last->data;
}
template <typename T>
int LinkedList<T>::Count(){
return m_count;
}
template <typename T>
LinkedList<T>::~LinkedList(){
while(m_count > -1){
Node* temp = m_first;
m_first = temp->m_next;
delete temp;//delete in destructor
m_count--;
}
}
So why I am not allowed to delete something that was newed somewhere else? Is it because it was newed outside the current scope?
您可以 delete
在其他地方 new
编辑。只要您指向有效地址,这就不是问题。当您随后尝试使用指向现在 delete
ed 地址的指针之一时,就会出现段错误。
Second, freeing the space works fine, but I feel that's like cheating!
您应该只在使用 malloc
时使用 free
,在使用 new
时才使用 delete
。你应该永远不要把它们混在一起。另外,在你delete
之后,养成了给指针变量赋值NULL
的习惯。
Because I may need things to be done on my Node's destructor.
封装数据的class内部也应该做自己的内存管理。例如,LinkedList
应该管理节点的内存。
这意味着,如果您有类似 LinkedList<T>::add(Node<T> *data)
的东西,您应该考虑 LinkedList<T>::add(T data)
之类的东西;然后列表 class 本身负责处理节点。
否则,您 运行 冒着将 new
ed 节点发送到列表中的风险,然后列表 delete
在某些时候在内部,但在其他地方,列表的客户端仍然持有对现在无效节点的引用。当客户端尝试使用它时,砰!:再次出现段错误。
What am I doing wrong? How to properly kill that removed node?
除了混合 new
s 和 free
s 之外,段错误很可能是由无效的内存访问触发的,因此您应该找到不再指向有效的指针(即 un deleted
) 内存。
有很多答案说 new/delete
和 malloc()/free()
应该总是这样配对,但我觉得应该说 为什么 完全正确。
与您的初始化一样,
Node<char> *h = new Node<char>('H');
new
关键字 returns 一个完整类型的对象对象指针,在语句本身中定义,而 malloc()
只是分配给定的内存 space 而没有分配类型,所以 returns 一个 void*
。此外,new/delete
处理来自 Free Store 的内存,而 malloc()/free()
allocate/free 堆上的内存,尽管某些编译器可能会根据 malloc()/free
在某些方面实现 new/free
实例。
还有一些重要的是 new
和 delete
分别调用构造函数和析构函数,而 malloc()
和 free()
只是分配和释放堆内存,没有考虑内存本身的状态。
这是对正确识别和解决 OP 的直接问题的其他答案的附录。需要快速浏览一下以解释接下来会发生什么。
Node<T> *temp = cur;
prev->next = cur->next;
cur = cur->next;
cur->prev = prev;
此时temp还没有被清除,所以next和prev仍然指向过去围绕cur的两个节点,现在链接在一起。如果不是这样,这将导致严重的问题:
free(temp); //Here is my problem!!!
free
失败,因为temp指向的值是new分配的。 NathanOliver 的回答涵盖了这一点,但隐藏在下面的是
delete temp;
这将调用析构函数来像清理小对象一样进行清理。不幸的是,Node
析构函数看起来像这样:
~Node() { delete next; delete prev; }
temp->next
仍然指向一个活节点。 temp->prev
也是如此。
下一个和上一个得到 delete
d。它调用它们的析构函数,delete
调用它们接触的两个节点,并调用将破坏列表中所有节点的死亡风暴。
如果双删不先杀程序。每个链接节点将尝试 delete
刚刚 deleted
它们的节点。不好。
很有可能 Node
析构函数应该只照顾自己,而将其他 Node
的析构留给 LinkedList
class.