Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет173/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   169   170   171   172   173   174   175   176   ...   256
Байланысты:
Бьерн Страуструп. Язык программирования С . М Бином, 2011

9.4 Запросы ресурсов 
Если в некоторой функции потребуются определенные ресурсы, например, нужно открыть файл, 
отвести блок памяти в области свободной памяти, установить монопольные права доступа и т.д., для 
дальнейшей работы системы обычно бывает крайне важно, чтобы ресурсы были освобождены 
надлежащим образом. Обычно такой "надлежащий способ" реализует функция, в которой происходит 
запрос ресурсов и освобождение их перед выходом. Например: 
void use_file(const char* fn) 

FILE* f = fopen(fn,"w"); 
// 
работаем с f 
fclose(f); 

Все это выглядит вполне нормально до тех пор, пока вы не поймете, что при любой ошибке, 
происшедшей после вызова fopen() и до вызова fclose(), возникнет особая ситуация, в результате 
которой мы выйдем из use_file(), не обращаясь к fclose(). Стоит сказать, что та же проблема возникает и 
в языках, не поддерживающих особые ситуации. Так, обращение к функции longjump()из стандартной 
библиотеки С может иметь такие же неприятные последствия. 
Если вы создаете устойчивую к ошибкам системам, эту проблему придется решать. Можно дать 
примитивное решение: 
void use_file(const char* fn) 

FILE* f = fopen(fn,"w"); 
try 

// работаем с f 

catch (...) { 
fclose(f); 
throw; 

fclose(f); 

Вся часть функции, работающая с файлом f, помещена в проверяемый блок, в котором 


Бьерн Страуструп.
Язык программирования С++ 
 
244 
перехватываются все особые ситуации, закрывается файл и особая ситуация запускается повторно. 
Недостаток этого решения в его многословности, громоздкости и потенциальной расточительности. К 
тому же всякое многословное и громоздкое решение чревато ошибками, хотя бы в силу усталости 
программиста. К счастью, есть более приемлемое решение. В общем виде проблему можно 
сформулировать так: 
void acquire() 

// запрос ресурса 1 
// 
... 
// запрос ресурса n 
// использование ресурсов 
// освобождение ресурса n 
// 
... 
// освобождение ресурса 1 

Как правило бывает важно, чтобы ресурсы освобождались в обратном по сравнению с запросами 
порядке. Это очень сильно напоминает порядок работы с локальными объектами, создаваемыми 
конструкторами и уничтожаемыми деструкторами. Поэтому мы можем решить проблему запроса и 
освобождения ресурсов, если будем использовать подходящие объекты классов с конструкторами и 
деструкторами. Например, можно определить класс FilePtr, который выступает как тип FILE* : 
class FilePtr { 
FILE* 
p; 
public: 
FilePtr(const char* n, const char* a) 
{ p = fopen(n,a); } 
FilePtr(FILE* pp) { p = pp; } 
~FilePtr() 

fclose(p); 

operator FILE*() { return p; } 
}; 
Построить объект FilePtr можно либо, имея объект типа FILE*, либо, получив нужные для fopen() 
параметры. В любом случае этот объект будет уничтожен при выходе из его области видимости, и его 
деструктор закроет файл. Теперь наш пример сжимается до такой функции: 
void use_file(const char* fn) 

FilePtr 
f(fn,"w"); 
// работаем с f 

Деструктор будет вызываться независимо от того, закончилась ли функция нормально, или произошел 
запуск особой ситуации. 


Достарыңызбен бөлісу:
1   ...   169   170   171   172   173   174   175   176   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет