嵌套的 QVector 指针内存处理

Nested QVector pointer memory handling

我继承了一个庞大的Qt5项目,其中累积的内存泄漏正在成为一个严重的问题。 (是的,内存泄漏应该很少被容忍,但在现实生活中预算和时间限制...)。

此 GUI 将图像数据读入体素对象 class,以图形方式显示。数据来自文件或缓冲区(如果实时获取)并存储为嵌套 qvector,即:

QVector < QVector <Voxel *> > cVoxel;

当从文件中读取图像时,cVoxel 使用 QVector.resize(0) 进行初始化。

cVoxel.resize(0);

打开保存到文件的图像时,会创建一个本地 Voxel 指针并将其推到 cVoxel 的末尾,每个像素一次,因此遍历所有行和列:

for (iRow = 0; iRow < nRows; ++iRow)
{
   for (iCol = 0; iCol < nCols; ++iCol)
   {
      Voxel *v = new Voxel;
      cVoxel[iRow].push_back(v);
      // Code for reading data into cVoxel removed here
      ...
   }
}

感谢下面有用的评论,我现在通过嵌套销毁 cVoxel,在 Windows 任务管理器中看到内存使用 减少 取得了一些成功我的 CTOR 中的 QVector。沿着:

for (iRow = 0; iRow < nRows; iRow++)
{
    for (iCol = 0; iCol < nCols; iCol++)
    {
        delete cVoxel[iRow][iCol];
    }
}

理想情况下,主要重写是最好的解决方案。但在现实世界中,我将不得不尝试修复更大的漏洞并希望这就足够了,直到有足够的资源可用于更理想的解决方案。

----编辑----

对下面乱七八糟的临时评论表示歉意,但这确实帮助我减少了内存泄漏(希望在适当的时候完全停止......)。

我在上面进行了在线编辑(希望)使这个 post 更清楚,并删除了我最好的案例工作,因为它对内存泄漏没有影响。上面的重大改动是 (2) 斜体的简短段落。

我还需要调查@richardcitter (sp?) 多态相关的建议。

--- EDIT3 ---

删除了 Edit2,post单独编辑了那个(新)问题

此外,我非常有信心下面的答案应该可以解决这个问题 - 我只需要弄清楚如何使用 qvector.resize() 或找到解决方法。

很难在评论中格式化代码,所以我将其添加为答案,即使它可能无法解决您的问题。无论如何,评论也相当长。

要解决未定义的行为并正确确保您不需要进行任何额外分配,您可以预先分配向量中的元素数量。当您调用 resize(0) 时,您已经这样做了,但不是设置您真正需要的大小,而是将大小设置为零,使向量为空。

我建议改为这样:

首先按照 Richard Critten 的建议使用 std::unique_ptr

QVector < QVector < std::unique_ptr <Voxel> > > cVoxel;

如果 Qt 有自己独特的指针类型,您可以使用它。

然后在创建时使用 resize 设置向量的 实际 大小:

cVoxel.resize(nRows);

然后你可以在向量中使用普通索引。也设置内部向量的大小:

for (iRow = 0; iRow < nRows; ++iRow)
{
   cVoxel[iRow].resize(nCols);  // Resize to the number of columns

   for (iCol = 0; iCol < nCols; ++iCol)
   {
      cVoxel[iRow][iCol].reset(new Voxel);  // Create the actual Voxel object

      // Code for reading data into cVoxel here
      ...
   }
}

由于您使用 std::unique_ptr(或 Qt 等价物),一旦对象被破坏,由 std::unique_ptr 对象管理的内存将自动释放。所以不再有内存泄漏,当 cVoxel 向量超出范围或以其他方式被破坏时,您的 Voxel 对象也会如此。

@SomeProgrammerDude:你让我得到了 9/10 的解决方案。我不知道我是应该编辑你的答案还是使用这个,所以版主请相应地编辑。

正如 中所述,我最终决定不使用智能指针。上面的解决方案(对我来说)介绍了编译器试图引用已删除函数的问题。否则,经过一些修改是正确的:

QVector < QVector <Voxel *> > cVoxel;

初始化:

cVoxel.resize(0);

内存分配:

{
   for (int i = 0; i < rows; ++i)
   {
      cVoxel.push_back( QVector <Voxel *> () );
      for (int j = 0 ; j < cols ; ++j)
      {
         Voxel *v = new Voxel;
         cVoxel[i].push_back(v);
      }
   }
}

最终DTOR释放内存:

   int iRow, iCol;
   for (iRow = 0; iRow < rows; iRow++)
   {
      for (iCol = 0; iCol < cols; iCol++)
      {
           delete cVoxel[iRow][iCol];
      }
   }