3

我有一个任务是使用一个列表编写一个 Stacks 类,并使用两个 Stacks 编写一个 Queue 类。我已经完成了任务,但是运行 valgrind 我发现我在以下代码中有内存泄漏:

T Stack<T>::pop()
{
    T *n = new T;
    *n = myStack.front();
    myStack.pop_front();
    return *n;
}

返回后我无法删除指针,所以我不确定如何修复它。提前致谢。

4

7 回答 7

4

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;

于 2012-10-12T06:26:40.130 回答
3

制作一个副本,然后在 pop_front 中清除内存(如果有)。

    T Stack<T>::pop()
    {
        T ret = myStack.front();
        myStack.pop_front();        
        return ret;
    }
于 2012-10-12T06:25:08.670 回答
0

T *n = 新 T;您正在使用 new 创建 T 而不是使用它。那就是问题所在。

于 2012-10-12T07:00:37.163 回答
0

您有多个答案给出了正确的代码,但是您现有代码错误的原因如下:

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...
} 
于 2012-10-12T06:45:10.280 回答
0

复制语义是 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++ 中抛出析构函数是被禁止的)。

于 2012-10-12T08:16:29.630 回答
0

你应该宁愿使用

T n = myStack.front();
于 2012-10-12T06:25:06.450 回答
0

在您的位置上,我将停止使用原始指针并更改为 shared_ptr。是安全得多。

于 2012-10-12T06:37:52.457 回答