【问题标题】:Leaking memory when not freeing internal cells?不释放内部单元时内存泄漏?
【发布时间】:2020-11-22 07:22:12
【问题描述】:

我的教授写了以下代码:

template <class T>
Set<T>& Set<T>::operator=(const Set<T>& set) {
  if (this == &set) return *this;
  T* data_temp = new T[set.size];
  try {
    for (int i = 0; i < size; ++i) {
      temp_data[i] = set.data[i];
    }
  } catch (...) {
    delete[] temp_data;
    throw;
  }
  delete[] data;
  data = temp_data;
  size = maxSize = set.size;
  return *this;
}

他指出temp_data[i] = set.data[I]; 调用operator=,我想知道为什么这不会泄漏内存?

例如,如果operator= 在第四个循环中失败,那么我们将删除temp_data,但是temp_data 中分配在operator= 代码中的前3 个单元格的值呢?我们不会释放他们。

【问题讨论】:

  • data_temp vs temp_data,这是一个错字吗?
  • 上面的代码没有内存泄漏。您关心的是哪个 operator=? Set&lt;T&gt;::operator=T::operator=
  • 上面的代码进行了一次分配和一次释放。因此它没有内存泄漏。可能在其他代码中分配的任何其他内存都是该其他代码的责任。如果其他代码也已正确编写,则不会发生内存泄漏。
  • @John 但是在 T::operator= 我们正在分配内存...
  • @Josh989 不,我们不是。是什么让你这么说?

标签: c++ exception memory-management memory-leaks try-catch


【解决方案1】:

例如,如果 operator= 在第 4 次循环中失败,那么我们将删除 temp_data,但是在 temp_data 中分配在 operator= 代码中的前 3 个单元格的值呢?我们不会释放他们。

new[] 在到达循环之前分配整个数组并在其中构造 allT 对象。 delete[] 销毁数组中的所有 对象,并释放整个数组。所以,T的构造函数和析构函数有责任正确初始化和终结T的数据成员。

循环只是更新数组中对象的数据成员的内容T::operator= 有责任根据需要正确复制和释放 T 的数据成员。

Set::operator= 代码中没有泄漏。但是有一个小错误——循环需要使用set.size 而不是size

for (int i = 0; i &lt; set.size; ++i)

新数组分配给set.size的元素数量,这就是循环需要复制的元素数量。

使用size 进行循环,如果分配给的Set 小于复制的Set,则新数组不会复制所有元素。如果分配给更大的Set,则循环将超出两个数组的范围。

如果您遇到泄漏,它必须位于 T::operator=T::~T() 中,您都没有显示。假设 Set::Set()Set::~Set() 正在正确初始化和释放 data,这是。

【讨论】:

  • 但是有一个小错误——循环需要使用 set.size 而不是 size。但它们是一样的
  • @Josh989 不,它们不一样。想一想将包含 5 个元素的 Set 分配给包含 10 个元素的 Set 时会发生什么。在循环中,size 仍为 10,set.size 仍为 5,因此循环越界尝试将 5 元素数组中的 10 个元素复制到另一个 5 元素数组中。
【解决方案2】:

让我们从这段代码中消除一些复杂性。让我们假设T == int,而不是存储许多ints,我们只存储一个:

int_store& int_store::operator=(const int_store& set)
{
    int* temp_data = new int;   (1) allocate
    try 
    {
        *temp_data = *set.data;   (2) assign
    }
    catch (...) 
    {
        delete temp_data;       (3) free temp
        throw;
    }
    delete data;                (4) free old 
    data = temp_data;
}

该方法有一个分配int* temp_data = new int (1)。它尝试将其他 sets 数据分配给该临时值 (2)。如果此操作失败,则必须删除 temp (3),否则我们可以用存储在 temp_data 中的新数据替换旧的 data,在此之前我们必须删除旧数据 (4)。

try 块中没有分配。函数中分配的所有内存要么被删除(当分配失败时),要么用于替换旧数据,在这种情况下旧的data之前被删除。

如果data 是一个数组而不是单个int(几乎)没有任何变化并且没有泄漏。您担心的元素已经分配在T* data_temp = new T[set.size]; 行中,然后delete[] temp_data; 将全部删除。

【讨论】:

    猜你喜欢
    • 2012-06-08
    • 2011-01-27
    • 2014-09-19
    • 2012-04-03
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2019-08-18
    • 2010-12-04
    相关资源
    最近更新 更多