Анимация
JavaScript
|
Главная Библионтека If (! std::с1п) { Поток cm находится в ошибочном состоянии Как и в случае с неявным преобразованием к логическому типу, этот оператор часто используется для совмещения чтения с проверкой результата: if (! (std::С1П » х)) { Попытка чтения завершилась неудачей Следующее выражение возвращает объект cin, к которому применяется оператор !; std::С1п » X Выражение после оператора ! необходимо заключить в круглые скобки из-за относительного приоритета операторов; без круглых скобок оператор ! будет выполнен первым. Другими словами, следующие два выражения эквивалентны: !std::С1п » X (!std::cin) » х Вряд ли это именно то, к чему стремился программист. Хотя описываемые операторы очень удобны, следует обратить внимание на одну странность: двойное отрицание не означает возвращения к исходному объекту: О cin - потоковый объект класса istream; О !!cin - логическая велт-гчина, описываюп1ая состояние объекта cin. Существует мнение, что преобразование к логическому значению не соответствует принципам хорошего стиля программирования. Функции типа fail() обычно делают программу более понятной: std::с1п » х; if (std::c1n.fa1l()) ( Состояние потока данных и исключения Механизм обработки исключений был включен в С++ д.ля выявления ошибок и особых ситуаций (см. с. 31). Тем не менее это было сделано уже после того, как потоки данных получили широкое распространение. Чтобы сохранить совместимость, потоки данных по умолчанию не генерируют исключений. Однако для каждого флага состояния стандартизированных потоков данных можно указать, до.лжна ли установка этого флага сопровождаться выдачей исключения. Для этой цели используется функция exceptions() (табл. 13.6).
При вызове без аргументов функция exceptions() возвращает текущие флаги, при установке которых генерируются исключения. Если функция возврашает goodbit, исключения не генерируются. Этот режим используется по умолчанию для поддержания совместимости. Если функция exceptions() вызывается с аргументом, то сразу же после установки соответствующего флага состояния будет выдано исключение. Следующий пример настраивает поток данных так, чтобы при установке любого флага генерировалось исключение: Генерировать исключение при любой "ошибке" strm.exceptions (std::ios::eofbit std::ios::failbit std::ios::badbit): Если аргумент равен О или goodbit, исключения не генерируются: Не генерировать исключения strm.exceptions (std::ios::goodbit); Исклточения генерируются при установке соответствующих флагов после вызова с1еаг() илн setstate(). Это происходит даже в том случае, если флаг был установлен ранее: Вызов генерирует исключение, если флаг failbit был установлен при входе strm.exceptions (std::ios::failbit); Следующая команда генерирует исключение (даже если флаг failbit был установлен ранее) strm.setstate (std::ios::failbit): Генерируемые исключения являются объектами класса std::ios base:;failure, производного от класса exception (см. с. 43). namespace std { class ios base::failure : public exception { public: Конструктор explicit failure (const string& msg); Деструктор virtual -failureO; Возврат информации об исключении virtual const char* whatO const: К сожалению, стандарт не требует, чтобы объект исключения содержал какую-либо информацию об ошибочном потоке данных или о типе ошибки. Существует единственный переносимый способ получения информации об ошибке - сообщение, возвращаемое функцией what(). Впрочем, переносим только вызов what(), но не возвращаемая строка. Если требуется дополнительная информация, программист должен сам заботиться о ее получении. Из этого поведения следует, что обработка исключений в большей степени ориентируется на непредвиденные ситуации. Собственно, поэтому она называется обработкой исключений, а не обработкой ошибок. Ожидаемые ошибки (например, ошибки форматирования при вводе данных пользователем) считаются «нормальными», а для их обработки лучше использовать флаги состояния. Основная область применения потоковых исключений - чтение предварительно отформатированных данных (например, автоматически сгенерированных файлов). Но даже в этом случае при обработке исключений возникают проблемы. Например, если данные читаются до конца файла, вы не сможете генерировать исключения ошибок без того, чтобы не получить исключение конца файла. Дело в том, что ири обнаружении конца файла также устанавливается бит failbit (признак неудачи при чтении объекта). Чтобы отличить конец файла от ошибки ввода, придется дополнительно проверить состояние потока данных. Следующий пример показывает, как зто делается. Функция readAndProcessSum читает вещественные числа из потока данных до тех пор, пока не достигнут конец файла. Затем возвращается сумма прочитанных вещественных чисел: io/sumla.cpp #include <istream> namespace MyLib { double readAndProcessSum [std::istreamS strm) using std::ios: double value, sum; Сохранение текущего состояния флагов исключений ios::iostate oldExceptions = strm.exceptionsO: /* Выдача исключений при установке флагов failbit и badbit * - ВНИМАНИЕ: флаг failbit также устанавливается * при достижении конца файла */ strm.exceptions Cios::failbit ios::badbit): try { /* Пока поток находится в нормальном состоянии * - прочитать Значение и прибавить его к сумме */ 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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 [ 186 ] 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |