1. Виды ошибок в runtime
- ошибки по вине программиста
int a[10];
for(int i = 0; i <= 10; i++) {
a[i] = i;
}
char s;
strlen(s);
- ошибки по вине окружения
пользователь ввел неправильные данные
на диске закончилось место
разорвалось сетевое соединение
2. Ошибки по вине программиста
- выявить ошибки на стадии отладкиж
assert(s != NULL), gcc -DNDEBUG
автотесты (google test)
3. Ошибки по вине окружения
- предусмотреть обработку ошибок
вывод сообщения об ошибке
освободить ресурсы (динамическая память, открытые файлы, ...)
поптыка восстановления (например, использование параметров по умолчанию вместо данных некорректного конфига)
4. С style
FILE* fin = fopen("a.txt", "r"); //одно из возвращаемых значений зарезервировано
if( fin == NULL ) {
// возможные причины: нет файла; нет прав; ...
printf("s\n", strerror(errno)); //errno --- глобальная переменная (код последней ошибки)
}
Недостатки:
- не всегда возможно зарезервировать значение под ошибку: atoi("0") == atoi("abbc")
- недостаточно информации об ошибки: код, текстовое сообщение, имя функции и т.д.
- перемещана логика работы и логика обработки ошибки
int res1 = robot.up();
if( res1 < 0 ){
//обработка
}
else {
int res2 = robot.down();
if( res2 < 0) {
//обработка
}
}
5. C++ style
- try/catch/throw
View::initModel --> Model::init --> Config::load
void Config::load(...) {
if (ошибка формата) {
throw FileException("Bad config format"); //бросить можно значение любого типа
}
}
void Model:init(...) {
try {
// блок логики работы
Config c;
c.load(this);
initMonsters();
initHeroes();
}
catch(FileException& e) {
// блок обработки ошибок
setDefaultValues();
// здесь нельзя вывести сообщение об ошибке, т.к. неизвестно,
// какой тип View текстовый или графический => передать ошибку дальше
throw e;
}
}
void View::initModel(...) {
try {
model.init();
createStartScreen();
}
catch(FileException& e) {
showMessageBox(e.message());
}
}
6. Детали
- поймать и пробросить ошибку любого типа
try {
doSomething()
}
catch(...) {
throw;
}
- stack unwinding
f() {
try {
g();
}
catch(MyException& e) {
}
}
g() {
h();
}
h() {
throw MyException();
}
- сработает первый подходящий catch (порядок важен)
class BaseException { };
class DerivedException : public class BaseException { };
try {
}
catch(DerivedException& de) {
}
cacth(BaseException& be) {
}