C ++ - 重载赋值运算符内存泄漏

时间:2014-08-22 21:24:14

标签: c++ memory-leaks operator-overloading copy-constructor assignment-operator

我有一个类方法,可以处理对象的副本(确切地说是*)。泄漏发生在重载的赋值运算符中 - 无论如何,这是Visual Leak Detector所说的。我正在做的是使用副本,如果完成的工作是令人满意的,我将新创建的对象复制回来。我还实现了自定义析构函数,复制构造函数和赋值运算符,因为问题出现在动态分配的内存中。我使用C ++的经验非常有限,因此代码中可能存在一些不好的东西。

如果需要,我会提供更多信息。

有问题的方法:

bool Grid::SurroundShipSquares(int top, int bottom, int left, int right)
{
    // copying itself
    Grid gridCopy(*this);
    Square** squaresCopy = gridCopy.GetSquares();
    for (int i = top; i <= bottom; ++i)
    {
        for (int j = left; j <= right; ++j)
        {
            if (squaresCopy[i][j].GetState() != SquareState::Vacant)
                return false;
            (squaresCopy[i][j]).SetState(SquareState::Unoccupiable);
        }
    }
    // the problem occurs here
    *this = gridCopy;
    return true;
}

复制构造函数:

Grid::Grid(const Grid& source)
{
    _position = source._position;
    _size = source._size;
    int dimensions = static_cast<int>(_size);
    _squares = new Square*[dimensions];
    for (int i = 0; i < dimensions; ++i)
    {
        _squares[i] = new Square[dimensions];
        for (int j = 0; j < dimensions; ++j)
        {
            _squares[i][j] = source._squares[i][j];
        }
    }
}

作业运营商:

Grid& Grid::operator=(const Grid& source)
{
    if (this == &source) 
        return *this;
    _position = source._position;
    _size = source._size;
    int dimensions = static_cast<int>(_size);
    _squares = new Square*[dimensions];
    for (int i = 0; i < dimensions; ++i)
    {
        _squares[i] = new Square[dimensions];
        for (int j = 0; j < dimensions; ++j)
        {
            _squares[i][j] = source._squares[i][j];
        }
    }
    return *this;
}

析构函数:

Grid::~Grid()
{
    int dimensions = static_cast<int>(_size);
    for (int i = 0; i < dimensions; ++i)
    {
        delete[] _squares[i];
    }
    delete[] _squares;
}

1 个答案:

答案 0 :(得分:5)

您的代码存在的问题是您手动管理所有资源。这是非常不安全的,并且正确地做了大量的头痛,正如现有的答案都是错误的恰当证明的那样。

使用std::vector。该课程将自动为您管理所有内存,让您不必自己动手。这将大大简化您的代码,并使其正确。

此外,自我分配检查是一种古老的反模式。不要包括自我分配的检查。如果您的赋值运算符(在大多数情况下,您不应该自己编写自己的基于std::vector的内存管理)在没有特殊情况下无法处理自我赋值,那么它就会被破坏。