исключение — C ++: освобождение и «наконец-то» эквивалент

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

Очевидно, что если бы он был в стеке, то RAII и размотка стека позаботились бы об этом, но я задавался вопросом, как лучше всего использовать динамически распределенную память.

Пример:

int copyInt(int n) throw(int) { // this function leaves exceptions for the caller to handle
int ret_val;
try {
int *arr = new int[n]; // dynamically allocate some memory for the computation
maybe_throw(arr);
for (int ii=0; ii<n; ++ii) arr[ii]=ii+1; // clever algorithm requiring n ints.
maybe_throw_again(arr);
ret_val = arr[n-1];                    // ----"----
} finally {       // syntax error, this is what you'd do in Java.
delete arr;   // prevent leak, whether exception occurs or not.
}
return ret_val;
}

1

Решение

Вообще говоря, используйте умный указатель управлять динамически размещаемым объектом (или массивом).

Типично std::unique_ptr<> : он будет гарантировать уничтожение вашего объекта, даже если будет сгенерировано исключение (по той же причине, что ваша цитата для объектов, размещенных в стеке: умные указатели являются обертками RAII вокруг динамически размещаемых объектов или массивов объектов)

Это работает одинаково хорошо для массивов:

1) Управляет временем жизни одного объекта (например, выделенного с новым)

2) Управляет временем жизни динамически распределенного массива объектов
(например, выделено с новым [])

По вашему коду 🙁 удаляем try/catch/finally так как уборка теперь происходит автоматически)

int copyInt(int n)
{
int ret_val;

std::unique_ptr<int[]> arr = std::unique_ptr<int[]>(new int[n]);
for (int ii=0; ii<n; ++ii)
arr[ii]=ii+1;

return arr[n-1]+1;
}
  • В вашем примере вы также можете рассмотреть std::array<> или же std::vector<> заменить массивы в стиле C, но это, вероятно, другой вопрос.
2

Другие решения

Лучше всего переписать ваш код для использования RAII. Стандартная библиотека C ++ имеет много контейнерных классов, чтобы помочь вам в этом; Эти контейнеры были разработаны с учетом исключительной безопасности.

В этом случае:

int copyInt(int n)
{
if ( n < 1 )
return 0;  // or throw something

std::vector<int> arr(n);
maybe_throw(&arr[0]);

// clever algorithm
std::iota( arr.begin(), arr.end(), 1 );

maybe_throw(&arr[0]);
return arr[n-1] + 1;
}

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

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

2

По вопросам рекламы [email protected]