Стоит ли освобождать массив, если выделение этого массива вызывает исключение? - PullRequest
0 голосов
/ 16 октября 2018

У меня есть потенциально нестабильный класс, который кто-то написал, и мне нужно создать массив объектов этого класса.Я упоминал, что класс нестабилен, поэтому он может иногда вызывать исключение в конструкторе по умолчанию.У меня нет доступа к исходному коду, только скомпилированные двоичные файлы.

Когда я выделяю динамический массив объектов такого типа, используя new, есть вероятность, что один из этих плохих объектов можетбросить исключение.Это выбрасывает пользовательское исключение, а не std::bad_alloc.В любом случае, мне нужно заставить программу восстановиться после исключения и просто продолжать пуск, хотя и устанавливаются некоторые флаги ошибок, а что нет.Я думаю, что я должен delete память, связанную с массивом, чтобы предотвратить утечку памяти.

Я считаю, что если класс генерирует исключение, создающее элемент где-то в середине массива, этот элемент выигралне будет построено должным образом, и все будущие элементы будут остановлены созданием исключения, но предыдущие элементы будут построены должным образом, поскольку это произошло до того, как было сгенерировано исключение.Мне интересно, это хорошая идея, чтобы позвонить delete в catch (...) { }?Как бы я решил эту утечку памяти?

Badclass* array = nullptr;

try {
  array = new Badclass[10];  // May throw exceptions!
} catch (...) {
  delete[] array;
  array = nullptr;
  // set error flags
}

Так я могу представить это в памяти.Это правильно?

 array         0    1    2    3   4    5 6 7 8 9
 ___          __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___|        |____|____|____|____|____|_|_|_|_|_|

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Чтобы ответить на последний вопрос:

Как бы я решил эту утечку памяти?

Нет утечки памяти.Утечка произошла бы только в том случае, если BadClass сам динамически распределял контент и никогда не освобождал его в своем деструкторе.Поскольку мы не обращаем внимания на вашу BadClass реализацию, а не занимаемся догадками, решать вам.Единственный способ new BadClass[N]; утечки памяти сам по себе - это когда она завершается, и вы позже выбрасываете единственную ссылку на нее, которой вы управляете вручную (array).

Массив, динамически выделяемый, выбрасывая в пределах одногоиз конструкторов для содержащихся в них элементов будет (а) возвращать деструкторы в обратном порядке для уже созданных элементов, (б) освобождать выделенную память и, наконец, (в) обрабатывать фактический бросок ближайшему обработчику перехвата (или обработчику по умолчанию, когдаих нет).

Поскольку происходит сброс, присваивание результирующему указателю массива никогда не происходит и поэтому не требует delete[].

Лучше всего продемонстрировано на примере:

#include <iostream>

struct A 
{
    static int count;
    int n;

    A() : n(++count)
    {
        std::cout << "constructing " << n << '\n';
        if (count >= 5)
            throw std::runtime_error("oops");
    }

    ~A()
    {
        std::cout << "destroying " << n << '\n';
    }
};

int A::count;

int main()
{
    A *ar = nullptr;
    try
    {
        ar = new A[10];
    }
    catch(std::exception const& ex)
    {
        std::cerr << ex.what() << '\n';
    }
}

Вывод

constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops

Обратите внимание, что поскольку построение элемента '5' никогда не завершалось, егодеструктор не уволен.Однако члены, которые были успешно построены , разрушены (не показано в примере выше, но это забавное упражнение, если вы готовы к этому).

Всетем не менее, используйте умные указатели независимо.

0 голосов
/ 16 октября 2018

Нет необходимости вызывать delete в случае исключения в:

array = new Badclass[10];  // May throw exceptions!

Нет утечки памяти.

В качестве ссылки читайте о новом выражении в cppreference :

Если инициализация завершается с помощью исключения (например, из конструктора), если новое выражение выделило какое-либо хранилище, вызывает соответствующую функцию освобождения: оператор delete для типа, не являющегося массивом, оператор delete [] для типа массива .

Так что ясно говорится, что delete[] вызывается автоматически, и вам не нужно его вызывать.

Если часть объектов была построена с помощью new[] до того, как было сгенерировано исключение, то все построенные объекты будут уничтожены до освобождения памяти.Это похоже на конструкцию объекта, которая содержит массив, и при создании какого-либо объекта в массиве возникает исключение.

0 голосов
/ 16 октября 2018

В следующей строке кода:

array = new Badclass[10];  

new Badclass[10] оценивается первым.Если это вызывает исключение, то выполнение не достигает назначения.array сохраняет прежнее значение, равное nullptr.Вызвать delete для nullptr.

не имеет никакого эффекта. Вопрос из раздела комментариев:

Основан ли этот тип поведения на том же принципе, что и разматывание стека?

Раздел «Обработка исключений» в стандарте помогает нам понять, что происходит, когда возникает исключение во время распределения.

18 Обработка исключений [исключением]
...
18.2 Конструкторы и деструкторы [exc.ctor]

1.Как управление переходит от точки, где исключение выдаетсяобработчик, деструкторы вызываются процессом , указанным в этом подпункте, , называемым разматыванием стека .
...
3.Если инициализация или уничтожение другого объектачем делегирование конструктора завершается исключением, деструктор вызывается для каждого из прямых подобъектов объекта и, для завершенного объекта, подобъектов виртуального базового класса, инициализация которых завершена иЭтот деструктор еще не приступил к исполнению, за исключением того, что в случае уничтожения альтернативные члены класса, подобного союзу, не уничтожаются.Субобъекты уничтожаются в порядке, обратном завершению их построения .Такое уничтожение выполняется до входа в обработчик функции-try-block конструктора или деструктора, если таковой имеется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...