Поведение, описанное спрашивающим, невозможно или
, когда деструктор скомпилирован как комментарий:
означает, что деструктор закомментирован, и это вызываетпротечь.Это было подтверждено в комментарии.Без деструктора последнее распределение никогда не будет отложено.
Настоящая проблема Аскера - это Правило Трех Нарушений.
Краткая версия выглядит примерно так:
Есликласс требует определенного пользователем конструктора копирования, оператора присваивания или деструктора, он почти всегда требует всех трех.
Подробнее об этом здесь: Что такое правило трех?
В этом случае
void printIntArray(DynamicArray<int> arr)
принимает arr
по значению.Это означает, что arr является копией переданного значения. В отсутствие пользовательского конструктора копирования arr
внутри printIntArray
будет указывать на то же распределение, что и источник.Копия будет уничтожена в конце printIntArray
, и деструктор удалит выделение, оставив источник, указывающий на недопустимую память, так что ...
DynamicArray<int> arr(5); // allocated storage inside arr
printIntArray(arr); // made a copy of arr that points to same storage.
// Storage freed when copy destroyed
arr.insert(1); // invokes undefined behaviour writing into invalid memory
arr.insert(2); // same
arr.insert(3); // same
printIntArray(arr); // copies arr again. This copy is pointing to the same invalid memory
// and will try to free the allocation a second time when the
// copy is destroyed
Программа почти наверняка потерпит крах, вызываяневозможно вытечь из кода пользователя.Но поскольку программа потерпела крах, Crom знает только то, какие закулисные структуры, которые использовала среда выполнения, не были правильно убраны.
Что бы ни случилось, по состоянию на
arr.insert(1);
программа была глубоко погружена в Неопределенное поведение и все, что происходит после этого, - чье-то предположение.Утечки памяти - это наименьшее количество ваших забот.
Исправление: удовлетворение правилу трех
Реализация конструктора копирования и оператора присваивания ( Мы пока проигнорируем правило пяти). )
Вы можете изменить
void printIntArray(DynamicArray<int> arr)
на передачу по ссылке
void printIntArray(DynamicArray<int> & arr)
, а затем
DynamicArray(const DynamicArray &) = delete;
DynamicArray& operator=(const DynamicArray &) = delete;
и отключить всекопирование, но это кажется немного драконовским.
Вместо позволяет использовать Copy и Swap , потому что это просто и легко понять.Обратите внимание, что это также может быть неэффективно, поэтому это не всегда правильный инструмент.Здесь это соответствует тому, что мы хотим.
DynamicArray(const DynamicArray & src) :
size(src.size), numOfElements(src.numOfElements), arr(new T[size])
{
for (int i = 0; i < numOfElements; i++)
{
arr[i] = src.arr[i];
}
}
DynamicArray& operator=(const DynamicArray src)
{
std::swap(size, src.size);
std::swap(numOfElements, src.numOfElements);
std::swap(arr, src.arr);
return *this;
}
И поскольку тем, кто хочет копировать, им не нужно, мы все равно будем
void printIntArray(DynamicArray<int> & arr)
, как только мы закончим тестирование этогоконструктор копирования работает правильно.