我有一个使用列表编写堆栈类和使用两个堆栈编写队列类的任务。我已经完成了任务,但是运行valgrind时,我发现以下代码中有内存泄漏:
T Stack<T>::pop()
{
T *n = new T;
*n = myStack.front();
myStack.pop_front();
return *n;
}
返回指针后我无法删除指针,因此我不确定如何修复它。提前谢谢。
为什么你甚至需要使用new?您可以像这样复制堆栈的最高值:
T Stack<T>::pop()
{
T n = myStack.front();
myStack.pop_front();
return n;
}
所以没有分配,也没有泄漏;
复制,然后清除内存(如果pop_front内有的话)。
T Stack<T>::pop()
{
T ret = myStack.front();
myStack.pop_front();
return ret;
}
你应该使用
T n = myStack.front();
在你的位置上,我会停止使用原始指针并更改为shared_ptr。是更安全。
你有多个答案给出了正确的代码,但你现有的代码是错误的原因是这样的:
T Stack<T>::pop()
{
T *n = new T; // allocates dynamic memory
*n = myStack.front(); // reference to T from front() copied to allocated T object
myStack.pop_front(); // removes the T in the stack
return *n; // copies your allocated T object to the return value
// your pointer variable goes out of scope, that address is stored nowhere,
// this is where the leak occurs...
}
*n = 新 T;您正在使用新的而不是使用它来创建 T。这就是问题所在。
复制语义是C++的最大优势之一,因为你可以把编译器和类型"T"的作者归咎于:
T Stack<T>::pop() // may throw
{
T ret = myStack.front();
myStack.pop_front();
return ret;
}
请注意,这是流行函数的次理想形式。复制时,可能会引发异常,这使得实现异常安全弹出函数基本上是不可能的。
容器std::stack<>
通过将返回类型设为void
来解决:
void Stack<T>::pop() // no-throw [if T is written by a sane coder]
{
myStack.pop_front();
}
T Stack<T>::back() // may throw
{
return myStack.front();
}
这为您提供了一种在销毁时清理堆栈而不引发异常的方法(按照惯例(而不是标准),禁止在C++中抛出析构函数)。