我在确保已为链接列表Node类创建了一个清除函数时遇到麻烦。我使用的delete this
会导致内存问题,但这是我可以确保删除链表中所有对象的唯一方法。 main()的最后几行仍将打印出应删除的头节点的值。这是方法中的错误,还是由于指针仍与对象相关联?
清除方法摘要
class Node {
private:
Node *next = NULL;
double value;
public:
void clear();
};
void Node::clear() {
cout << "Clear: " << this << ":" << value << endl;
if(next != NULL){
next -> clear();
}
delete this;
}
完整文件
using namespace std;
class Node {
private:
Node *next = NULL;
double value;
public:
Node(double);
Node getNext(){return *next;} //inline
void setNext(Node *newNext); //set *next
double getValue(){return value;} //inline
void setValue(double newValue) {value = newValue;} //inline
void incValue(); //Increment value by the value of next node's value. If next is NULL do nothing.
int sizeOf(); //return size of linked list
double largest(); //return largest value in linked list
double smallest(); //return smallest value in linked list
double getSum(); //Get summation of all
double average(); //return average of all values in the linked list
void print(); //print all values in linked list
void print_reverse(); //print all values in reverse order
void clear(); //remove all nodes from linked list
};
Node::Node(double newValue) {
value = newValue;
}
void Node::setNext(Node *newNext) {
next = newNext;
}
void Node::incValue() {
if(next != NULL) {
double nextVal = next -> getValue();
value += nextVal;
}
}
int Node::sizeOf() {
int count = 0;
if(next != NULL)
count = next -> sizeOf();
count += 1;
return count;
}
double Node::largest() {
double large = value;
if(next != NULL)
large = next -> largest();
if(value > large)
large = value;
return large;
}
double Node::smallest() {
double small = value;
if(next != NULL)
small = next -> smallest();
if(value < small)
small = value;
return small;
}
double Node::average() {
double sum = getSum();
int size = sizeOf();
return sum/size;
}
double Node::getSum() {
double sum = 0;
int count = 0;
if(next != NULL)
sum += next -> getSum();
sum += value;
return sum;
}
void Node::print() {
cout << value << endl;
if(next != NULL)
next -> print();
}
void Node::print_reverse() {
if(next != NULL)
next -> print_reverse();
cout << value << endl;
}
void Node::clear() {
cout << "Clear: " << this << ":" << value << endl;
if(next != NULL){
next -> clear();
}
delete this;
}
int main() {
//set up linked list
Node *head, *temp;
temp = new Node(1);
head = temp;
temp = new Node(2);
temp -> setNext(head);
head = temp;
temp = new Node(3);
temp -> setNext(head);
head = temp;
temp = new Node(4);
temp -> setNext(head);
head = temp;
temp = new Node(5);
temp -> setNext(head);
head = temp;
temp = new Node(6);
temp -> setNext(head);
head = temp;
temp = new Node(7);
temp -> setNext(head);
head = temp;
temp = new Node(8);
temp -> setNext(head);
head = temp;
//print
cout << "Print\n";
head -> print();
//average
cout << "Average\n";
double av = head -> average();
cout << av << endl;
//print reverse
cout << "Print reversed\n";
head -> print_reverse();
//smallest
cout << "Smallest\n";
double small = head -> smallest();
cout << small << endl;
//largest
cout << "Largest\n";
double large = head -> largest();
cout << large << endl;
//size
cout << "Size\n";
int size = head -> sizeOf();
cout << size << endl;
//clear
cout << "Clear\n";
head -> clear();
//clear print
cout << "Clear print\n";
head -> print();
cout << "Clear size\n";
cout << head -> sizeOf() << endl;
//end of program
cout << "End\n";
}
答案 0 :(得分:2)
您应该很少(如果有的话)使用delete this;
。您也没有清除next
指针,因此它变成了悬空指针。该内存可能仍包含那里的许多数据,因此在“清除”列表后遍历列表时,您会看到旧的数据,但是请注意,这只是其中的 个可能发生许多事情,因为访问已被破坏的对象是未定义的行为。
相反,请考虑这样做:
void Node::clear() {
cout << "Clear: " << this << ":" << value << endl;
if(next != NULL){
next -> clear();
delete next;
next = NULL;
}
}
更好的是,在Node的析构函数中执行此操作,然后您可以删除目标节点:
void Node::~Node() {
clear();
}
void Node::clear() {
cout << "Clear: " << this << ":" << value << endl;
if(next != NULL){
delete next;
next = NULL;
}
}
甚至更好,将next
设为std::unique_ptr
,然后您可以在clear()
上将其重置,销毁是自动的,并且正确地禁止复制节点:
class Node {
private:
std::unique_ptr<Node> next;
double value;
public:
void clear();
};
void Node::clear() {
cout << "Clear: " << this << ":" << value << endl;
next.reset(null);
}
请注意,最后一个节点(头)无法删除自身。正如其他人所指出的那样,清除节点除了停止指向下一个节点之外,无法进行任何其他操作。您需要为列表创建一个单独的类,然后清除它。
答案 1 :(得分:1)
clear()
之后的所有内容都是未定义的行为,因为在head
函数中已删除了变量clear
。您可以在垃圾回收之后考虑打印。
关于释放所有内容的正确方法,应将清除函数放在Node
结构之外:
void clear(Node* head)
{
Node* next = head->next;
delete head;
if (next != nullptr)
clear(next);
}
我认为在析构函数中调用delete是UB,因为delete会为您调用析构函数。如评论中所述,在析构函数中不存在delete
,忘记了我说的话!