Утечка памяти, когда не освобождаются внутренние ячейки? - PullRequest
0 голосов
/ 01 августа 2020

Мой профессор написал следующий код:

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= не удалось в 4-м oop, тогда мы удаляем temp_data, но как насчет значений первых 3 ячеек в temp_data, которые были выделены внутри operator= кода? мы их не освобождаем.

Ответы [ 2 ]

1 голос
/ 01 августа 2020

Например, если operator= не удалось в 4-м oop, тогда мы удаляем temp_data, но как насчет значений первых 3 ячеек в temp_data, которые были выделены внутри operator= кода ? мы не освобождаем их.

new[] выделяет весь массив и создает в нем все из T объектов, прежде чем будет достигнуто l oop. delete[] уничтожает все объектов в массиве и освобождает весь массив. Итак, конструктор и деструктор T должны правильно инициализировать и завершить элементы данных T.

l oop просто обновляет содержимое из элементы данных объектов в массиве. T::operator= несет ответственность за правильное копирование и освобождение элементов данных T по мере необходимости.

В этом коде Set::operator= нет утечки. Однако есть небольшая ошибка - l oop необходимо использовать set.size вместо size.

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

Новый массив выделяется на set.size количество элементов, так что именно столько элементов l oop необходимо скопировать.

Использование size для l oop, если назначенное Set меньше, чем Set скопировано, новый массив не скопирует все элементы. И если присвоить Set, который больше, l oop будет go за пределами обоих массивов.

Если у вас возникла утечка, она должна быть в любом T::operator= или в T::~T(), ни один из которых вы не показали. Предполагая, что Set::Set() и Set::~Set() правильно инициализируются и освобождают data, это будет.

0 голосов
/ 01 августа 2020

Давайте удалим некоторые сложности из этого кода. Предположим, что T == int, и вместо того, чтобы хранить множество int s, мы сохраняем только один:

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). Он пытается назначить другие данные set s этому временному значению (2). Когда это не удается, temp необходимо удалить (3), иначе мы можем заменить старые data новыми данными, хранящимися в temp_data, и перед этим мы должны удалить старые данные (4).

В блоке try нет выделения. Вся память, выделенная в функции, либо удаляется (при сбое присвоения), либо используется для замены старых данных, и в этом случае старый data удаляется раньше.

Если data вместо этого является массивом одиночного int (почти) ничего не меняется и течи нет. Элементы, о которых вы беспокоитесь, уже выделены в строке T* data_temp = new T[set.size];, а затем delete[] temp_data; удалит их все.

...