Исключение при создании 2D Array: очистка перед повторным выбросом в C ++

0

Я хочу иметь функцию, которая динамически создает и возвращает 2D-массив или когда сбой памяти не проходит исключение без потери информации после очистки уже выделенных строк:

double **create (int rows, int cols)
{
    double **array = new double* [rows];
    for (int x=0; x<rows; x++)
    {
        try { array[x] = new double [cols]; }
        catch (exception &e)
        {
            x--;
            for (; x>=0; x--)
                delete[] array[x]; // clean up already allocated rows
            delete[] array;
            throw e; // pass exception
        }
        for (int y=0; y<cols; y++)
            array[x][y] = 0; // initialize array
    }
    return array;
}

Поэтому я могу быть уверен, что если вы создаете броски, утечки памяти нет. Но могу ли я быть уверенным, что прошедшее исключение e является "таким же", как если бы оно было направлено новым и не выловлено?

Например

int main ()
{
    double **d;
    try { d = create (HUGE_x, HUGE_y); }
    catch (exception &e)
    {
        // 1. e could be thrown by new double* [rows]
        //      e.g. if HUGE_x is already to huge
        // 2. e could be thrown by throw e
        //      e.g. if after some rows no memory anymore
        // in both cases: is e the same?
    }
    return 0;
}

Или необходимо, чтобы catch (bad_alloc &e) внутри функции create? Или это работает только с catch (...) {/* do clean-up*/throw; } catch (...) {/* do clean-up*/throw; }? Есть ли та же проблема, что и в С# с потерей трассировки стека при повторном броске не с throw; просто?

И еще один, более общий вопрос:

void f () { throw Object(); } // or throw "help";

void main ()
{
    try { f(); }
    catch (Object &e) // or catch (char *)
    {
        // Where is the Object or C-String created on the stack in function f()
        // since we aren't any more in function f() but we are dealing with
        // references/pointers to a non-existent stack?
    }
}
Теги:
multidimensional-array
exception
stack-trace
rethrow

1 ответ

4
Лучший ответ

Для безопасного управления памятью используйте RAII. Вместо того, чтобы манипулировать необработанными указателями и обработчиками исключений, назначьте ресурс классу, который выведет его на уничтожение. Таким образом, все будет очищено автоматически, если будет выбрано исключение.

В этом случае std::vector является подходящим классом RAII, управляющим динамическим массивом:

vector<vector<double>> create (int rows, int cols) {
    return vector<vector<double>>(rows, vector<double>(cols));
}

(Обратите внимание, что может быть более эффективным представлять 2D-массив в виде единого массива rows*cols, с помощью аксессуаров для его двумерного индексирования. Но это не по теме для этого вопроса, поэтому я не буду вдаваться в утомительную деталь).

Чтобы ответить на ваши вопросы, хотя они в значительной степени не имеют значения, если вы пишете безопасный код:

Но могу ли я быть уверенным, что прошедшее исключение e является "таким же", как если бы оно было направлено новым и не выловлено?

Это не будет; вы бросаете новый объект, созданный путем копирования или перемещения e, с exception типа.

Или необходимо, чтобы catch (bad_alloc &e) внутри функции create?

Тогда вы не поймаете другие типы исключений. В этом случае это может не помешать, но вы действительно хотите поймать все исключения, если вы собираетесь это делать. Повторить: не используйте обработчики исключений для очистки. Он очень подвержен ошибкам.

Или это работает только с catch (...) {/* do clean-up*/throw; } catch (...) {/* do clean-up*/throw; }?

Это восстановит исходный объект, который вы хотите. (За исключением того, что вы не должны вообще ловить что-либо).

Есть ли та же проблема, что и в С# с потерей трассировки стека при повторном броске не с throw; просто?

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

Где объект или C-строка?

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

  • 0
    vector<vector> - не лучший способ создания 2D-массива
  • 0
    @llnk: Возможно, нет, но это минимальное изменение по сравнению с double** в вопросе. Я мог бы добавить примечание об альтернативах, но это становится довольно не по теме.
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню