【问题标题】:C++ - overloaded assignment operator memory leaksC++ - 重载赋值运算符内存泄漏
【发布时间】:2014-10-16 19:44:42
【问题描述】:

我有一个类方法可以处理对象的副本(准确地说是 *this)。泄漏发生在重载的赋值运算符中 - 无论如何,这就是 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;
}

【问题讨论】:

  • 省去所有麻烦,改用copy-and-swap idiom
  • 不幸的是,这个问题再次证明了为什么我最近在 SE 网络的这一部分的参与度下降了。
  • @DavidHammen 很抱歉出现这种情况,但我肯定不是罪魁祸首。我所做的只是发布一个诚实的新手问题。
  • @Venom:你肯定不是罪魁祸首。一方面,您应该认真考虑使用标准库中的工具。另一方面,您最终需要学会编写安全代码并正确管理资源。在这个网站上有一群连续投票者不会让其他人回答你问题的后半部分。做丹尼尔弗雷在他的评论中所说的。学习复制和交换习语。你应该考虑使用 std::vector 如果它适合你的需要
  • @DavidHammen 您完全可以按照自己的方式回答问题。其他人认为它有害,他们(在评论部分)向您解释了原因。这是他们的选择。停止整个抱怨受害。

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


【解决方案1】:

您的代码的问题在于您手动管理所有资源。这是非常不安全的,而且要正确地做是一件非常头疼的事情,现有的两个答案都是错误的,这一点恰如其分地证明了这一点。

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

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

【讨论】:

  • 我可以使用 valarray 来存储 2D 矩阵吗?我问是因为它肯定会保持固定尺寸。像这样,例如 - std::valarray<:valarray>()> _squares.
  • 您可以这样做,但请考虑使用 boost::multi_array 。无论如何,您现有的代码等效于向量向量。 std::valarray 有点像没有人喜欢或使用的孤儿。最终,容器的确切选择取决于您,取决于您想要表达的确切语义,并且在这里比首先使用容器更重要。通常,程序员只使用向量,除非他们特别需要使用其他东西。
  • 我注意到在编译时仍然需要知道 multi_array 的大小,不幸的是,这在我的情况下不起作用。在我之前的评论中,我的意思是容器大小,一旦最初确定,在其整个生命周期内保持不变。 C++14 提出了一个 dynarray,但显然还没有可用的实现。
  • 对动态大小的数组使用std::vector,对静态大小的数组使用std::array。这很简单。
  • @Venom:不。MSVC 发出一大堆完全虚假的警告。如果警告是从 Boost 代码中发出的,则忽略它 - Boost 开发人员已经在寻找它。基本上没有人使用 /W4,因为编译器会发出很多无用的警告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 2013-04-20
  • 1970-01-01
  • 2015-06-26
  • 1970-01-01
  • 2016-05-08
相关资源
最近更新 更多