В каком порядке память должна быть освобождена в C ++? - PullRequest
1 голос
/ 23 мая 2019

У меня небольшие затруднения с пониманием правильной последовательности событий, которые должны происходить при использовании оператора delete в C ++. Я усвоил, что правильный способ использовать это, когда указатель все еще ссылается на pointee.

В приведенном ниже примере - я копирую содержимое массива в temp, а затем delete [] старый массив, на который указывал мой arrayPointer.

Затем я указываю arrayPointer на вновь созданный массив и устанавливаю ненужный temp на nullptr. Я хочу убедиться, что я не вызываю утечки памяти, не удаляя временный указатель. Это все еще должно произойти?

Я спрашиваю, потому что я видел примеры, когда мы сначала указываем на nullptr, а затем delete, но это кажется нелогичным. Любое руководство будет с благодарностью. Спасибо!

    template <class T>
    void ValSet<T>::add(T elementToAdd){
        if(!this->contains(elementToAdd)){

            if(sizeOfArray == numOfElements){
                sizeOfArray *= 2;
                T* temp = new T[sizeOfArray];
                for (int i = 0; i < numOfElements; i++)
                    temp[i] = arrayPointer[i];
                delete [] arrayPointer;
                arrayPointer = temp;
                temp = nullptr;
            }
        numOfElements += 1;
        arrayPointer[numOfElements-1] = elementToAdd;
        }
      }

Ответы [ 2 ]

1 голос
/ 23 мая 2019

Как указано в комментариях к вашему сообщению, ваше решение верное.

Чтобы более подробно объяснить, почему вы правы, вы позаботились о том, чтобы выделить больше памяти, прежде чем скопировать и удалить свои текущие данные.,Это единственный порядок вещей: резерв (новый массив), копирование, резервирование (старый массив).(Во всяком случае, так я это помню.)

Более подробно: temp - это указатель, а не сам массив.Это очень важный и часто неправильно понимаемый момент.Я много с этим боролся, лично.Итак, когда вы просто говорите T* temp;, вы выделяете место для указателя в вашем текущем кадре.Когда вы говорите T* temp = new T[size];, вы выделяете место для указателя в текущем кадре И запрашиваете больше места (равное sizeof(T) * size байт) в другом месте памяти.

Это означает, что temp, какУказатель - это локальная переменная, но на которую он указывает, это не так.Когда вы присваиваете arrayPointer = temp;, вы говорите, что ваши элементы данных указывают, где temp указывает, но это не равно temp в том смысле, что это локальная переменная.Вот почему вы хотите delete[] arrayPointer перед тем, как назначить его равным temp, иначе вы никогда не сможете восстановить память, на которую указывал arrayPointer.Наконец, когда вы говорите arrayPointer = temp;, ничего в памяти, на которую указывает temp, не копируется;только значение (указатель) temp копируется в arrayPointer (поэтому вам нужно явно скопировать элементы исходного массива в новый массив, но не наоборот).Затем, когда ваш процесс выходит из этого фрейма, все локально объявленные переменные освобождаются, поэтому temp удаляется как указатель, но то, на что он указывал, не освобождается, потому что оно не было в фрейме (даже если оно было выделено вкадр).

Пара профессиональных советов: вместо цикла for я рекомендую взглянуть на std::copy, а temp = nullptr; на самом деле излишне, поскольку память, выделенная для temp(как локальная переменная) будет освобождена, как только функция вернется (как обсуждалось выше).

Надеюсь, это немного поможет концептуально.Но, опять же: вы определенно правы:)

0 голосов
/ 23 мая 2019

Если p имеет значение nullptr, то delete p ничего не делает.

Если вы видели примеры людей, устанавливающих необработанный указатель на нуль и затем удаляющих его, эти примеры были неверным кодом.

Установка указателя на nullptr никак не влияет на основную память, на которую он указывал ранее - это ключевое отличие между C ++ и большинством языков с подсчетом ссылок или сборщиком мусора.

С другой стороны есть множество классов «интеллектуальных указателей», реализующих семантику подсчета ссылок;std::shared_ptr является самым известным.Так что, возможно, вы видели кого-то, кто использует один из них.Для них, как правило, сброс указателя на ноль уменьшит его счетчик ссылок, в результате чего он будет удален, если счетчик ссылок был равен 1. Но это будет обработано классом;ты бы не позвонил delete сам.

...