Я динамически распределяю часть памяти внутри функции и хочу убедиться, что она освобождена независимо от того, произошло ли исключение.
Очевидно, что если бы он был в стеке, то 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;
}
Вообще говоря, используйте умный указатель управлять динамически размещаемым объектом (или массивом).
Типично 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, но это, вероятно, другой вопрос.Лучше всего переписать ваш код для использования 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
; функции без спецификации исключений также могут оставлять исключения для вызывающей стороны.
Я бы рекомендовал просто не использовать спецификацию исключений в этом случае. Если вы используете его, то вам следует включить обработку для любых исключений, которые не соответствуют спецификации, в противном случае плохой идеей будет использовать ее в первую очередь (так как это предотвращает дальнейшее отслеживание исключения функциями).