我有一个任务是使用一个列表编写一个 Stacks 类,并使用两个 Stacks 编写一个 Queue 类。我已经完成了任务,但是运行 valgrind 我发现我在以下代码中有内存泄漏:
T Stack<T>::pop()
{
T *n = new T;
*n = myStack.front();
myStack.pop_front();
return *n;
}
返回后我无法删除指针,所以我不确定如何修复它。提前致谢。
我有一个任务是使用一个列表编写一个 Stacks 类,并使用两个 Stacks 编写一个 Queue 类。我已经完成了任务,但是运行 valgrind 我发现我在以下代码中有内存泄漏:
T Stack<T>::pop()
{
T *n = new T;
*n = myStack.front();
myStack.pop_front();
return *n;
}
返回后我无法删除指针,所以我不确定如何修复它。提前致谢。
Why do you even need to use new? You can make a copy of the stack's top value like this:
T Stack<T>::pop()
{
T n = myStack.front();
myStack.pop_front();
return n;
}
So there are no allocations and no leaks;
制作一个副本,然后在 pop_front 中清除内存(如果有)。
T Stack<T>::pop()
{
T ret = myStack.front();
myStack.pop_front();
return ret;
}
T *n = 新 T;您正在使用 new 创建 T 而不是使用它。那就是问题所在。
您有多个答案给出了正确的代码,但是您现有代码错误的原因如下:
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...
}
复制语义是 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++ 中抛出析构函数是被禁止的)。
你应该宁愿使用
T n = myStack.front();
在您的位置上,我将停止使用原始指针并更改为 shared_ptr。是安全得多。