Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 [ 73 ] 74 75 76

исключение в случае переполнения диска при записи, чего легко добиться на дискете. Более того, функция write() не возвращает никакого кода ошибки. Перехват исключения является единственным способом обнаружения ошибки. Вот пример того, как вы должны обнаруживать ошибку чтения:

char data[128];

Cfile f( "some file", CFile::modeWrite ); try

f.Write( data, sizeof(data) );

catch( CFileException &r )

if( r.m cause == CfileException::diskFull ) что-то сделать

Имеется две проблемы. Первая явно связана с уродливостью этого кода. Я бы гораздо охотнее написал:

bytes written = f.Write( data, sizeof(data)); if( bytes written != sizeof(data) ) разобраться с этим

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

Даже когда Write() возвратила количество записанных байтов, то вы все еще не можете исправить ошибку. Например, даже если функцию CFile переписать, как показано ниже, то она все равно не будет работать:

char data[128];

CFile f( "some file", CFile::modeWrite ); int bytes written;

bytes written = f.Write( data, sizeof(data) );

catch( CFileException &r )



14 Я определил это для 32-разрядного компилятора Visual С++ Microsoft; другие компиляторы показывают или сравнимые результаты, или худшие.

if( r.m cause == CFileException::diskFull ) что-то выполнить.

при этом переменная bytes written содержит мусор.

Управление передается прямо откуда-то изнутри Write() в обработчик catch при возбуждении исключения, перескакивая через все операторы return внутри Write(), а также через оператор присваивания в вызывающейся функции; переменная bytes written остается неинициализированной. Я думаю, что вы могли бы передать Write() указатель на переменную, которую она могла использовать для хранения числа записанных байтов перед тем, как выбросить исключение, но это не будет значительным улучшением. Лучшим решением будет отказ от возбуждения исключения и возврат или числа записанных байтов, или какого-то эквивалента индикатора ошибки.

Последней проблемой являются непроизводительные затраты. Обработка исключения вызывает очень большие непроизводительные затраты, выражающиеся в возрастании в несколько раз размера кода и времени выполнения. Это происходит даже в операционных системах типа Microsoft Windows NT, которые поддерживают обработку исключений на уровне операционной системы. Вы можете рассчитывать на 10-20% увеличение размера кода и падение скорости выполнения на несколько процентов при интенсивном использовании исключений. Следовательно, исключения должны использоваться лишь тогда, когда непроизводительные затраты не берутся в расчет; обычно, при наличии возможности, предпочесть возврат ошибки.

160. По возможности возбуждайте объекты типа error

Листинг 1 5 показывает простую систему определений класса для возбуждения исключений. Я могу перехватить ошибки чтения или записи подобным образом:

file f("name", "rw"); buffer b; b = f.readO; f.write( b );

catch( file::open error &r )



Файл не существует или не может быть открыт.

catch( file::io error &r )

Какая-то из неисправим1х ошибок ввода/вывода.

Если меня волнует лишь то, что произошла ошибка определенного вида, и не волнует, какого конкретно, то я могу сделать так:

file f;

buffer b; b = f.readO f.write( b );

catch( file::error &r )

...

Листинг 15. Классы исключений 1 class file

3 public:

4 class error {};

5 class open error : public error {};

6 class io error : public error {}; 7

8 ...

Этот код работает, потому что объект file::read error является объектом типа file::error (так как относится к производному классу). Вы всегда можете перехватить объект производного класса, используя ссылку или указатель базового класса.

Я мог бы также предложить другой класс, использующий тот же самый механизм:

class long double

public:

class error {};

class didvide by zero : public error {}; ...

Так как классы error являются вложенными определениями, то именами на самом деле являются file::error и long double::error,



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 [ 73 ] 74 75 76