Книга: Программист-прагматик. Путь от подмастерья к мастеру
Балансировка и исключения
Разделы на этой странице:
Балансировка и исключения
Языки, поддерживающие исключения, могут сделать процедуру освобождения ресурса нетривиальной. Как удостовериться, что все ресурсы, назначенные до возбуждения исключения, освобождены надлежащим образом? В некоторой степени ответ зависит от языка программирования.
Балансировка ресурсов в исключениях языка С++
Язык С++ поддерживает механизм исключений типа try…catch. К сожалению, это означает, что всегда существует по крайней мере два возможных варианта выхода из подпрограммы, которая перехватывает, а затем повторно возбуждает исключение:
void doSomething(void) {
Node *n = new Node;
try {
// do something
}
catch (…) {
delete n;
thow;
}
delete n;
}
Заметим, что созданный нами узел освобождается дважды – один раз во время нормального выхода из подпрограммы, а второй раз в обработчике исключений. Это явное нарушение принципа DRY и проблема в сопровождении, которая может возникнуть в любой момент.
Однако в наших интересах воспользоваться семантикой языка С++. Локальные объекты автоматически разрушаются при выходе из блока, в котором они находятся. Это дает нам несколько вариантов. Если обстоятельства позволяют, можно поменять n: оно обозначает не указатель, а реальный объект Node в стеке:
void doSomething1(void) {
Node n;
try {
// делаем что-либо
}
catch (…) {
throw;
}
}
В этом случае мы используем С++ для автоматического разрушения объекта Node независимо от того, возбуждено исключение или нет.
В случае, если замена указателя на объект невозможна, тот же самый эффект достигается при инкапсулировании ресурса (речь идет об указателе Node) в пределах другого класса.
// Класс оболочки для ресурсов Node
class NodeResource {
Node *n;
public:
NodeResource() {n = new Node;}
~NodeResource() {delete n;}
Node *operator ->() {return n;}
};
void doSomething2(void) {
NodeResource n;
try {
// do something
}
catch (…) {
throw;
}
}
Теперь класс-оболочка NodeResource выступает гарантом того, что при разрушении его объектов происходит и разрушение соответствующих узлов. Для удобства класс оболочка предоставляет оператор разыменования – », с тем чтобы пользователи могли обращаться к полям в инкапсулированном объекте Node напрямую.
Поскольку эта методика столь полезна, в стандартной библиотеке С++ имеется шаблонный класс autOjDtr, обеспечивающий автоматические оболочки для динамически размещаемых объектов.
void doSomething3(void) {
auto_ptr <Node> р (new Node);
// Обращение к узлу Node как р-»…
// В конце узел автоматически удаляется
}
Балансировка ресурсов в языке Java
В отличие от C++ язык Java реализует «ленивую» форму автоматического разрушения объекта. Объекты, ссылки на которые отсутствуют, считаются кандидатами на попадание в «мусор», и их метод finalize будет вызываться в любой момент, когда процедура сборки мусора будет претендовать на эти объекты. Представляя собой удобство для разработчиков, которым больше не приходится жаловаться на утечки памяти, в то же время он усложняет реализацию процедуры очистки ресурсов по схеме С + +. К счастью, разработчики языка Java глубокомысленно ввели компенсирующую языковую функцию – предложение finally. Если блок try содержит предложение finally, то часть программы, относящаяся к этому предложению, гарантированно исполняется только в том случае, если исполняется любая инструкция в блоке try. Неважно, возбуждается при этом исключение или нет (даже при выполнении оператора return программой в блоке try) – программа, относящаяся к предложению finally, будет выполнена. Это означает, что использование ресурса может быть сбалансировано с помощью программы типа:
public void doSomething() throws IOException {
File tmpFile = new File(tmpFileName);
FileWriter tmp = new FileWriter(tmpFile);
try {
// do some work
}
finally {
tmpFile.delete();
}
}
Подпрограмма использует промежуточный файл, который мы хотим удалить, независимо от того, как подпрограмма заканчивает свою работу. Блок finally позволяет нам выразить это в сжатой форме.
- 25 Балансировка ресурсов
- Объекты и исключения
- Случаи, при которых балансировка ресурсов невозможна
- 1.2.7. Исключения
- 3.6. Шаг 5. Балансировка ассортимента по глубине
- Исключения и обработчики исключений
- Рассмотрите возможность исключения необязательной информации перед отправкой данных на устройство
- Ода ошибкам и исключениям
- Балансировка нагрузки
- Исключения, возникающие при выполнении операций над числами с плавающей точкой
- Ошибки и исключения
- Исключения, генерируемые приложением