我已经使用c ++中的链接列表构建了一个堆栈,但是有人告诉我,整个事情一文不值,因为我的析构函数不能高效地完成其工作,所以有人可以告诉我如何为该代码构建析构函数。据我了解,构造函数的工作是删除未使用的内存,我提到的析构函数还有其他功能吗? 任何帮助将不胜感激。
#include <iostream>
#include <string>
#include <limits>
using namespace std;
class Stack
{
private:
struct node
{
int data;
node* next;
node()
{
int data = 0;
next = nullptr;
}
};
node* top;
public:
Stack()
{
top = nullptr;
}
~Stack()
{
delete top;
}
void push(int n)
{
node* temp = new node;
temp->data = n;
temp->next = top;
top = temp;
}
int pop()
{
node* temp = top;
top = top->next;
return temp->data;
}
int peek()
{
return top-> data;
}
bool isEmpty()
{
return top == 0;
}
};
int main()
{
Stack stack;
std::string command;
while (true)
{
std::cout << "stack>";
std::cin >> command;
try
{
if (command == "pop")
{
if (stack.isEmpty())
{
throw std::runtime_error("error: stack is empty");
}
std::cout << stack.pop() << std::endl;
}
else if (command == "push")
{
int n;
if (!(std::cin >> n))
{
throw std::runtime_error("error: not a number");
}
stack.push(n);
}
else if (command == "peek")
{
if (stack.isEmpty())
{
throw std::runtime_error("error: stack is empty");
}
std::cout << stack.peek() << std::endl;
}
else if (command == "end")
{
while (!(stack.isEmpty()))
{
std::cout << stack.pop() << std::endl;
}
return 0;
}
else
{
throw std::runtime_error("error: invalid command");
}
}
catch (std::runtime_error& e)
{
std::cin.clear();
std::cin.ignore(numeric_limits<streamsize>::max(), '\n');
std::cerr << std::endl << e.what() << std::endl;
}
}
return 0;
}
答案 0 :(得分:1)
您在Stack::pop()
方法中发生内存泄漏,而您的Stack()
析构函数仅删除top
,因此,如果元素多于1个,则还会有另一个泄漏。处理动态分配的内存时,最好使用智能指针:
class Stack
{
struct node;
using node_ptr = std::unique_ptr<node>;
private:
struct node
{
int data;
node_ptr next;
node(int n, node_ptr nxt) : data(n), next( std::move(nxt) )
{ // your old ctor has a bug, you "initialized" local variable
}
};
node_ptr top;
Stack() = default;
~Stack()
{
while(top)
top = std::move( top->next );
}
int pop()
{
node_ptr temp = std::move(top);
top = std::move(temp->next);
return temp->data;
}
void push(int n)
{
top = std::make_unique<node>(n,std::move(top));
}
int peek() const
{
return top->data;
}
bool isEmpty() const
{
return !top;
}
};
您的代码变得更小,更容易理解,并且没有以前的泄漏。您不必提供显式的Stack
析构函数,但是效率低下(执行递归调用,但仍然正确)。提供的析构函数更加高效。
答案 1 :(得分:0)
您有一个这样的列表:
top---->node->node->node->node->...
在Stack
的析构函数中,删除top
指向的对象。您剩下的是:
node->node->node->...
请注意,大多数节点尚未删除,并且由于不再指向它们,因此不再有删除它们的方法。这称为内存泄漏。
要修复析构函数,必须删除列表中的每个节点。提示:使用循环;复制下一个指针,删除当前节点,然后继续下一个指针。
析构函数不是堆栈泄漏的唯一地方。 pop
无法删除顶级节点,然后再将其从列表中取消链接。
此外,分配或处理Stack
对象将导致两个对象具有相同的列表,并因此尝试将其删除两次(分别在每个对象的析构函数中一次)。该行为将是不确定的。每当在析构函数中管理资源时,总是需要定义一个副本(并移动)构造函数和也要管理资源的赋值运算符。这称为3的规则(移动操作为5)。如果您不希望类是可复制的(或可移动的),则可以声明它们已删除。
拥有裸露的指针是一个糟糕的设计。更好的设计是使用std::unique_ptr
您的node
构造函数使data
成员未初始化。我认为您的堆栈不会读取默认的初始化节点,因此这可能不成问题,但是您可能对编写的构造函数有不同的期望。
答案 2 :(得分:0)
您需要为while链接列表分配内存:
~Stack()
{
while(top)
{
struct node* curr = top;
top = top->next;
delete curr;
}
top = nullptr;
}
答案 3 :(得分:0)
您仅删除顶部元素。
尝试将~node() { delete next; }
添加到您的node
结构中。
并确保其NULL
终止,以使其停止!