Многоточие в обработчике catch
Broker
, могла сделать что-то полезное с исключением, например записать куда-нибудь соответствующее сообщение об ошибке.В catch
dev1_
, так как последнее выбрасывание исключения возможно только в операторе new
для dev2_
. Если он выбрасывает исключение, то переменной dev2_
не будет присвоено никакого значения и, следовательно, мне не нужно удалять объект dev2_
. Однако, если вы что-то делаете после инициализации dev2_
, вам потребуется выполнить зачистку этого объекта. Например:try {
dev1_ = new Device(devno1);
dev2_ = new Device(devno2);
foo_ = new MyClass(); // Может выбросить исключение
} catch (...) {
delete dev1_;
delete dev2_;
throw;
}
В этом случае вам не следует беспокоиться об удалении указателей, которым никогда не присваивались реальные значения (если изначально вы не инициализировали их соответствующим образом), поскольку удаление указателя NULL
dev1_
приводит к выбрасыванию исключения, ваш catch
-обработчик все же выполнит оператор delete dev2_
, однако все будет нормально, если вы инициализировали его значением NULL
в списке инициализации.Как я говорил в рецепте 9.1, рассматривая основы обработки исключений, для обеспечения гибкой стратегии обработки исключений может потребоваться особая ловкость, и то же самое относится к обеспечению безопасности исключений. Подробное рассмотрение методов проектирования программного кода, безопасного при исключениях, приводится в книге «
Рецепт 9.3.
9.3. Создание безопасного при исключениях списка инициализации
Необходимо инициализировать ваши данные-члены в списке инициализации конструктора, и поэтому вы не можете воспользоваться подходом, описанным в рецепте 9.2.
Используйте специальный формат блоков try
catch
, предназначенный для перехвата исключений, выбрасываемых в списке инициализации. Пример 9.3 показывает, как это можно сделать.#include
#include
using namespace std;
// Некоторое устройство
class Device {
public:
Device(int devno) {
if (devno == 2)
throw runtime error("Big problem");
}
~Device() {}
private:
Device();
};
class Broker {
public:
Broker (int devno1, int devno2)
try : dev1_(Device(devno1)), // Создать эти объекты в списке
dev2_(Device(devno2)) {} // инициализации
catch (...) {
throw; // Выдать сообщение в журнал событий или передать ошибку
// вызывающей программе (см. ниже обсуждение)
}
~Broker() {}
private:
Broker();
Device dev1_;
Device dev2_;
};
int main() {
try {
Broker b(1, 2);
} catch(exception& e) {
cerr << "Exception: " << e.what() << endl;
}
}
Синтаксис обработки исключений в списках инициализации немного отличается от традиционного синтаксиса С++, потому что здесь блок try
Broker
.Broker(int devno1, int devno2) // Заголовок конструктора такой же Constructor
try : // Действует так же, как try {...}
dev1_(Device(devno1)), // Затем идут операторы списка
dev2_(Device(devno2)) { // инициализации
// Здесь задаются операторы тела конструктора.
} catch (...) { // catch обработчик задается *после*