如果我删除链表元素,为什么调用 class 析构函数?
Why class destructor called if I delete linked list element?
我想通过删除程序末尾的所有节点来释放内存,但我也有删除特定节点的函数(重载运算符)。如果我要删除特定节点 class,则调用析构函数。谁能解释一下原因,以及如何解决它。
Class声明
class StudentList
{
private:
typedef struct student_node
{
student_node* prevSt;
//######Student DATA######
string surname;
string name;
string father_name;
Date birthday;
int year;
string faculty;
string departament;
string group;
string ID_number;
string sex;
//########################
SessionList session_data;
int session_count;
//########################
student_node* nextSt;
}* student_nodePtr;
student_nodePtr headSt;
student_nodePtr currSt;
student_nodePtr tailSt;
student_nodePtr tempSt;
public:
StudentList();
~StudentList();
StudentList operator-(student_nodePtr selectedSt);
};
构造函数、析构函数和重载运算符
StudentList::StudentList()
{
headSt = NULL;
currSt = NULL;
tailSt = NULL;
tempSt = NULL;
}
StudentList::~StudentList()
{
cout << "What!?" << endl;
}
StudentList StudentList::operator-(student_nodePtr selectedSt)
{
if(headSt == NULL || selectedSt == NULL)
{
return *this;
}
if(headSt == selectedSt)
{
headSt = selectedSt->nextSt;
}
if(tailSt == selectedSt)
{
tailSt = selectedSt->prevSt;
}
if(selectedSt->prevSt != NULL)
{
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
delete selectedSt;
return *this;
}
Here i'm choosing to Delete (2 2 2 2) guy
Here destructor appears for some reason
将 *this
作为 StudentList
返回时,您正在创建一个 临时 对象并返回它 - 这会导致析构函数调用。我认为这将 起作用, 即使在这样的语句中也是如此:
myList = myList - oneEntry - anotherEntry - aThird;
这是因为在每次减法时创建的临时文件用于下一次减法,最后的临时文件被分配给 myList
。
但是,这些减法中的每一个都可能会导致 new 临时,这将变得相当昂贵,尤其是对于较大的列表。
您最好返回一个引用,StudentList&
,这样就不需要临时对象并返回原始对象。
你的代码中更有问题的是,假设学生形成了一个 双 链表,你可能应该在 operator-
中有一些东西来调整反向指针以及前锋。
您当前的实现正确地处理了空列表并删除了 head/tail,但随后 只是 这个:
if(selectedSt->prevSt != NULL) {
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
这会调整前一个节点(如果有),使其现在指向下一个节点。但是,后面的节点仍然会指向即将被删除的节点作为它的前一个节点。也就是说,会出现这样的情况:
+------+ +------+
| node |---------------------->| node |
| | +--| |
+------+ +--------------+ | +------+
| deleted node |<-+
+--------------+
您需要执行两个 方向以保持一致的双向链表:
if(selectedSt->prevSt != NULL) { // forward link (already done).
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
if(selectedSt->nextSt != NULL) { // backward link (need to add).
selectedSt->nextSt->prevSt = selectedSt->prevSt;
}
否则,如果您决定反向遍历,您的列表将会损坏并导致严重问题。
您已这样声明您的 operator-
:
StudentList operator-(student_nodePtr selectedSt);
请注意,它是 returnStudentList
对象按值。这意味着调用代码正在接收一个临时 StudentList
对象,该对象在超出范围时会被销毁;因此调用了 StudentList
析构函数。
声明这样的运算符的通常方法是将其 return 改为引用:
StudentList & operator-(student_nodePtr selectedSt);
...这样就不会创建临时 StudentList
对象,但如果需要,仍然可以将对运算符的调用链接在一起。
我想通过删除程序末尾的所有节点来释放内存,但我也有删除特定节点的函数(重载运算符)。如果我要删除特定节点 class,则调用析构函数。谁能解释一下原因,以及如何解决它。
Class声明
class StudentList
{
private:
typedef struct student_node
{
student_node* prevSt;
//######Student DATA######
string surname;
string name;
string father_name;
Date birthday;
int year;
string faculty;
string departament;
string group;
string ID_number;
string sex;
//########################
SessionList session_data;
int session_count;
//########################
student_node* nextSt;
}* student_nodePtr;
student_nodePtr headSt;
student_nodePtr currSt;
student_nodePtr tailSt;
student_nodePtr tempSt;
public:
StudentList();
~StudentList();
StudentList operator-(student_nodePtr selectedSt);
};
构造函数、析构函数和重载运算符
StudentList::StudentList()
{
headSt = NULL;
currSt = NULL;
tailSt = NULL;
tempSt = NULL;
}
StudentList::~StudentList()
{
cout << "What!?" << endl;
}
StudentList StudentList::operator-(student_nodePtr selectedSt)
{
if(headSt == NULL || selectedSt == NULL)
{
return *this;
}
if(headSt == selectedSt)
{
headSt = selectedSt->nextSt;
}
if(tailSt == selectedSt)
{
tailSt = selectedSt->prevSt;
}
if(selectedSt->prevSt != NULL)
{
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
delete selectedSt;
return *this;
}
Here i'm choosing to Delete (2 2 2 2) guy
Here destructor appears for some reason
将 *this
作为 StudentList
返回时,您正在创建一个 临时 对象并返回它 - 这会导致析构函数调用。我认为这将 起作用, 即使在这样的语句中也是如此:
myList = myList - oneEntry - anotherEntry - aThird;
这是因为在每次减法时创建的临时文件用于下一次减法,最后的临时文件被分配给 myList
。
但是,这些减法中的每一个都可能会导致 new 临时,这将变得相当昂贵,尤其是对于较大的列表。
您最好返回一个引用,StudentList&
,这样就不需要临时对象并返回原始对象。
你的代码中更有问题的是,假设学生形成了一个 双 链表,你可能应该在 operator-
中有一些东西来调整反向指针以及前锋。
您当前的实现正确地处理了空列表并删除了 head/tail,但随后 只是 这个:
if(selectedSt->prevSt != NULL) {
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
这会调整前一个节点(如果有),使其现在指向下一个节点。但是,后面的节点仍然会指向即将被删除的节点作为它的前一个节点。也就是说,会出现这样的情况:
+------+ +------+
| node |---------------------->| node |
| | +--| |
+------+ +--------------+ | +------+
| deleted node |<-+
+--------------+
您需要执行两个 方向以保持一致的双向链表:
if(selectedSt->prevSt != NULL) { // forward link (already done).
selectedSt->prevSt->nextSt = selectedSt->nextSt;
}
if(selectedSt->nextSt != NULL) { // backward link (need to add).
selectedSt->nextSt->prevSt = selectedSt->prevSt;
}
否则,如果您决定反向遍历,您的列表将会损坏并导致严重问题。
您已这样声明您的 operator-
:
StudentList operator-(student_nodePtr selectedSt);
请注意,它是 returnStudentList
对象按值。这意味着调用代码正在接收一个临时 StudentList
对象,该对象在超出范围时会被销毁;因此调用了 StudentList
析构函数。
声明这样的运算符的通常方法是将其 return 改为引用:
StudentList & operator-(student_nodePtr selectedSt);
...这样就不会创建临时 StudentList
对象,但如果需要,仍然可以将对运算符的调用链接在一起。