我在Python和Java方面经验丰富,但最近我决定学习C ++。我决定做一个快速的整数堆栈实现,但它有一个我无法理解的大量内存泄漏。当我弹出节点时,它似乎没有释放内存,即使我在弹出它时明确删除旧节点。当我运行它时,它使用150mb的内存,但在我清空堆栈后不会释放任何内存。我很感激任何帮助,因为这是我第一次涉足没有垃圾收集的语言。这是在64位Kubuntu上用gcc 4.3编译的。
//a trivial linked list based stack of integers
#include <iostream>
using namespace std;
class Node
{
private:
int num;
Node * next;
public:
Node(int data, Node * next);
int getData();
Node * getNext();
};
Node::Node(int data, Node * next_node)
{
num = data;
next = next_node;
}
inline int Node::getData()
{
return num;
}
inline Node* Node::getNext()
{
return next;
}
class Stack
{
private:
unsigned long int n;
Node * top;
public:
Stack(int first);
Stack();
void push(int data);
int pop();
int peek();
unsigned long int getSize();
void print();
void empty();
};
Stack::Stack(int first)
{
Node first_top (first, NULL);
top = &first_top;
n = 1;
}
Stack::Stack()
{
top = NULL;
n = 0;
}
void Stack::push(int data)
{
Node* old_top = top;
Node* new_top = new Node(data,old_top);
top = new_top;
n++;
}
int Stack::pop()
{
Node* old_top = top;
int ret_num = old_top->getData();
top = old_top->getNext();
delete old_top;
n--;
return ret_num;
}
inline int Stack::peek()
{
return top->getData();
}
inline unsigned long int Stack::getSize()
{
return n;
}
void Stack::print()
{
Node* current = top;
cout << "Stack: [";
for(unsigned long int i = 0; i<n-1; i++)
{
cout << current->getData() << ", ";
current = current->getNext();
}
cout << current->getData() << "]" << endl;
}
void Stack::empty()
{
unsigned long int upper = n;
for(unsigned long int i = 0; i<upper; i++)
{
this->pop();
}
}
Stack createStackRange(int start, int end, int step = 1)
{
Stack stack = Stack();
for(int i = start; i <= end; i+=step)
{
stack.push(i);
}
return stack;
}
int main()
{
Stack s = createStackRange(0,5e6);
cout << s.peek() << endl;
sleep(1);
cout << "emptying" <<endl;
s.empty();
cout << "emptied" <<endl;
cout << "The size of the stack is " << s.getSize()<<endl;
cout << "waiting..." << endl;
sleep(10);
return 0;
}
答案 0 :(得分:5)
你怎么知道内存没有发布?运行时库将管理分配,并且在程序终止之前可能不会将内存释放回操作系统。如果是这种情况,则在执行期间,内存将可用于程序中的其他分配。
然而......你似乎还有其他问题。我的C ++真的很生疏,因为我已经做了15年的Java,但是在你的Stack :: Stack构造函数中,你在系统堆栈上分配一个Node实例,然后在你的“Stack”中存储一个对它的引用。当构造函数结束时,该Node实例超出范围,留下一个悬空指针。
答案 1 :(得分:3)
Stack::Stack(int first)
{
Node first_top (first, NULL);
top = &first_top;
n = 1;
}
这是错误的,你不能将本地对象的地址分配给类成员(顶部),因为当函数返回时本地对象会被销毁。
在堆而不是堆栈上创建一个节点,执行以下操作:
Stack::Stack(int first)
{
top = new Node(first, NULL);
n = 1;
}
并明确链接列表的概念,如果可以,请使用笔和纸。
您的Stack :: Push(int)操作似乎有问题,请查看您忘记做的事情。
我的建议是尝试在模板的帮助下实现通用堆栈,因此它适用于所有数据类型。
答案 2 :(得分:2)
当createStackRange()
返回时,它将使用编译器生成的复制构造函数返回堆栈的副本,该复制构造函数只进行按位复制(即,它将指针复制到第一个节点和大小。)
更严重的是,你错过了Stack
类的析构函数。理想情况下,您可以遍历列表并在每个Node
上调用delete。当main()退出时,处理器堆栈上创建的Stack
对象将自动自动清除,但如果没有析构函数,程序结束时仍将分配节点。你可能想要这样的东西:
Stack::~Stack()
{
while ( top )
{
Next *next = top->getNext();
delete top;
top = next;
}
}
考虑它的方法是C ++编译器会自动为您生成复制构造函数和析构函数,但它们通常很浅。如果你需要深度行为,你必须自己在某个地方实现它。
答案 3 :(得分:1)
在仔细查看代码之后,我找不到泄漏,所以我编译了它并自己在调试器中运行它。我同意Jim Garrision的观点 - 我认为你看到了运行时的工件,而不是实际的泄漏,因为我没有看到它在我身边。 NickLarsen和smith 指出的问题都是你要纠正的实际问题,但是如果你跟踪代码,实际上也不应该导致你描述的问题。在您的示例中,代码史密斯单身人士从未被调用过,而尼克单挑出来的代码会导致其他问题,但不会出现您所看到的问题。
答案 4 :(得分:0)
创建存根以测试您的代码和用户内存分析工具,如“Valgrind”。这将为您找出内存泄漏和损坏。
检查手册页以获取更多信息。
答案 5 :(得分:0)
请注意,您应该只为了教育目的而推出自己的堆栈。对于任何实际代码,您应该使用C ++标准库附带的堆栈实现...