Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.01.2011, 22:24   #1
Dayman
Форумчанин
 
Аватар для Dayman
 
Регистрация: 12.01.2011
Сообщений: 186
По умолчанию Обработка ошибок в проекте

Заранее извиняюсь за длинный пост.
Есть необходимость обработки ошибок в проекте, о котором пара слов ниже.
Проект пишется на QT под MSVC. Будет (да, проекта еще нету, где-то между стадией проектирования и "как же сложно начинать писать новый проект") иметь минимум 5 динамических библиотек + GUI, абстрагированный от всех библиотек кроме двух: первая является сборной солянкой из классов и структур, которые содержат данные, с которыми надо работать; вторая - предоставляет API для работы с этими данными.

И вот тут надо реализовать обработку ошибок. От исключений не отказываюсь, но использовать их как-то не хочется.
В голову приходит реализация класса с перечисляемыми типами и массивами строк. И реализация для каждого класса, в котором надо ловить ошибки метода getLasError, который будет возвращать код ошибки.
Тогда можно будет сделать, чтобы методы класса возвращали bool, и в случае false мы бы вызывали getLastError. Однако неясно что делать, если метод должен возвращать что-либо кроме void; можно конечно упрятать возвращаемый тип в аргументы со ссылкой или указателем, но как-то ненаглядно вызовы получаются тогда.
Также непонятно как передавать коды ошибок в GUI, особенно при многопоточности.

Код из одной из моих прог.
Код:
enum eGenericCodes{SXFOK=0,fileEntriesNumMismatch,
    GENERICCODESCURMAXVAL,GENERICCODESMAXVAL=100};
    // Passport Error Codes. [101;200] Reserved values
enum ePassportCodes{passNotSXFPassport=101,passSizeMismatch,passWrongFormatRevision,passCRCMismatch, .....
        PASSCODESCURMAXVAL,PASSCODESMAXVAL=200};

const _char* POOL::szGenericCodes[]={_("SXFOK"),_("Неверное количество объектов, либо файл поврежден")};

const _char* POOL::szPassportCodes[]={_("Не SXF Формат"),_("Несовпадение размера"),_("Неверная версия"),_("Чексумма неверна"),
.....
CURMAXVAL и MAXVAL нужны для проверки выхода за пределы char массива. Нужный индекс массива высчитывался исходя из кода возврата.
Тут был 1 класс, который всем рулил, так что особых переживаний по поводу как оно все будет вместе работать не было. Но вот сейчас дело другое: классов много и каждый из них должен иметь свои enum'ы ну и использовать некоторые общие коды (например файл не найден).

В общем есть ли идеи, советы, примеры как это реализуется в достаточно крупных проектах?

На всякий случай включаю примерную диаграмму что чего должно вызывать в проекте.
GUI
Core (API), DataTypes
DB module, Parsers, File I/O module, DataTypes, HTTP Handler
Lingua c++ non penis caninus est.
Dayman вне форума Ответить с цитированием
Старый 21.01.2011, 22:40   #2
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

В Qt не принято использования исключений для обработки ошибок. Так повелось. Это стиль, вырабатываемый годами. На прикладном уровне в Qt никто исключений не использует и все живут счастливо. Кроме того, в некоторых ситуациях это повышает производительность и упрощает портирование на разные платформы.

Но если свербит, можно переделать QApplication::notify() и ловить эксепшны там: http://doc.qt.nokia.com/latest/excep...rom-exceptions

И лучше бы ты писал в раздел про Qt.

Не по теме скажу теперь. Лучше именовать возможные значение в enum'ах как-то понятнее. Посмотрите, как это сделано в Qt. Вот например: http://doc.qt.nokia.com/latest/qgrap...ationFlag-enum
Даже если вы скажете QGraphicsView::DontSavePainterState , то из названия понятно, частью какого enum'а оно является.

Ну или вот примеры:
Код:
enum WindDirection {
    Windless,
    WestWind,
    SouthWind,
    NorthWind,
    EastWind
};

enum SomeErrors {
    OutOfMemory,
    MalformedInput
};
Ну и раз уж используешь Qt, зачем хранишь строки как символьные массивы? Используй QString!
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 21.01.2011 в 22:51.
Obey-Kun вне форума Ответить с цитированием
Старый 21.01.2011, 22:50   #3
Dayman
Форумчанин
 
Аватар для Dayman
 
Регистрация: 12.01.2011
Сообщений: 186
По умолчанию

К QT имеет мало отношения, для информации написал. Меня больше интересует реализация такого метода отлова ошибок в достаточно крупном проекте.
Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
Это стиль, вырабатываемый годами.
Ну у меня есть пара недель :D
Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
Даже если вы скажете QGraphicsView::DontSavePainterState , то из названия понятно, частью какого enum'а оно является.
Ну у меня тоже понятно имхо. Но в моем примере один класс, методы которого работают с разными структурами, которые требуют совершенно других кодов возврата.
То есть вы предлагаете делать enum в проверяемом классе, вместо какого-то общего класса ошибок?
Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
Ну и раз уж используешь Qt, зачем хранишь строки как символьные массивы? Используй QString!
Жирновато будет. Особые прибамбасы QString не используются в пояснениях к ошибкам, к тому же русского языка не будет.
Lingua c++ non penis caninus est.

Последний раз редактировалось Dayman; 21.01.2011 в 22:58.
Dayman вне форума Ответить с цитированием
Старый 21.01.2011, 22:53   #4
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

QT, о котором ты говоришь, пишется как Qt. Это не аббревиатура. И читается Qt как «кьют». А QT — это QuickTime.
А хорошие проекты проектируются так, чтобы обработка исключений не понадобилась.
Для отладки своей программы очень удобно использовать маркосы Qt Q_ASSERT и Q_ASSERT_X. И ещё Q_CHECK_PTR. Но в релизе (при QT_NO_DEBUG) они уже ничего не будут проверять (и это правильно, т.к. релиз это релиз).
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 21.01.2011 в 22:55.
Obey-Kun вне форума Ответить с цитированием
Старый 21.01.2011, 23:04   #5
Dayman
Форумчанин
 
Аватар для Dayman
 
Регистрация: 12.01.2011
Сообщений: 186
По умолчанию

Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
А хорошие проекты проектируются так, чтобы обработка исключений не понадобилась.
Коды возврата будут не столько для исключительных ситуаций, сколько для информационных "уведомлений".
Вообще исключительных ситуаций я не планирую. Все должно проверяться. Выход где-нибудь за пределы массива не предусмотрен, такого просто не должно быть.
А вот обрабатывать FileNotFound, HTTPRequestTimeout и, например, прочие ответы HTTP сервера или появление непредусмотренных полей при парсинге какого-то файла я как раз и хочу.
Lingua c++ non penis caninus est.

Последний раз редактировалось Dayman; 21.01.2011 в 23:27.
Dayman вне форума Ответить с цитированием
Старый 22.01.2011, 00:20   #6
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Если ошибка совсем плохая, то типа qFatal, если нет, то qCritical.
Ну а для засовывание этого в мессейдж бокс используй qInstallMsgHandler.

Вот например:
Код:
bool parseFile(const QFile &file) {
    // ...
    // ...
    while ( /*парсим файл*/ ) {
        // ...
        if ( /*плохая строка*/ ) {
            qCritical("Bad input bla-bla-bla");
            return false;
        }
    }
    return true;
}

void something(const QFile &file ) {
    if (parseFile(file)) { 
        // do something
    } else {
        // do something else
    }
}
И в том же духе.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 22.01.2011 в 00:31.
Obey-Kun вне форума Ответить с цитированием
Старый 22.01.2011, 00:52   #7
Dayman
Форумчанин
 
Аватар для Dayman
 
Регистрация: 12.01.2011
Сообщений: 186
По умолчанию

Видимо я очень плохо объясняю.
Забудьте про Qt В модулях нету GUI (кроме того, который так и называется - GUI), а показывать messagebox из парсера я точно не буду.
Мне хотелось бы узнать как лучше реализовать обработку ошибок с помощью кодов возврата:
  1. Один класс, который хранит enum'ы кодов и строки-пояснения для всех проверяемых классов; проверяемые классы содержат метод getLastError
  2. свои enum'ы и строки пояснения в каждом проверяемом классе; проверяемые классы содержат метод getLastError
  3. Что-то еще о чем я не знаю
И как лучше проверять эти самые методы, для пояснения:
  1. метод bool GetABC; тут все ясно. Получили false, вызываем getLastError
  2. метод someobject* GetABC; тут можно проверять надо ли вызывать getLastError по значению возвращаемого указателя (NULL).
  3. метод int GetABC; вот тут неясно; либо вызывать getLastError в любом случае, либо сделать bool GetABC(int&) переместив возвращаемое значение в аргументы; хотелось бы конечно сократить количество лишних вызовов getLastError
Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
Если ошибка совсем плохая, то типа qFatal, если нет, то qCritical.
Ну а для засовывание этого в мессейдж бокс используй qInstallMsgHandler.
Если спроецировать ваш пример на мое приложение, то плохая строка может иметь несколько кодов возврата: от FileNotFound до различных нюансов читаемого формата. Причем FileNotFound - sort of fatal. Приложение конечно не упадет, но уведомить надо, для других кодов уведомлений может и не понадобиться (допустим в настройках выставили галку автоматически приводить файлы древнего формата к новому), тем не менее код должен быть сгенерирован в любом случае. Однако на примере модуля парсеров, уведомление сначала пойдет в Core API, и только оттуда его сможет забрать GUI.
Lingua c++ non penis caninus est.

Последний раз редактировалось Dayman; 22.01.2011 в 01:02.
Dayman вне форума Ответить с цитированием
Старый 22.01.2011, 01:05   #8
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Тогда я бы так сделал:
Код:
namespace mycore
{
Class MyParser {
    // ...
    enum MyParseStatus {
        BadBracket,
        WrongSymbol,
        NoParseErrors
    }
    
    MyParseErrors parseFile(const QFile &file) {
        // ...
        // ...
        while(/*парсим файл*/) {
            // ...
            if(/*плохая скобочка*/) {
                return BadBracket;
            }
        }
        return NoParseErrors;
    }
};
}

namespace mygui
{
class MyParseGui
{
    // ...
    void tryToParse(const mycore::File &file) {
        // ...
        switch(myparser->parseFile(file)) {
        case BadBracket:
            // ...
            break;
        case NoParseErrors:
            // ...
            break;
        }
        // ...
    }
};
}
Кстати. У меня программа разбита на ядро и гуй, но я Qt везде использую, тем более ядро я разрабатываю вместе с гуём. В ядре я Qt использую как минимум для использования Qt'шных контейнеров. Правда, собирать в отдельную библиотеку ядро не собираюсь, это ни к чему, хотя это и возможно.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su

Последний раз редактировалось Obey-Kun; 22.01.2011 в 01:13.
Obey-Kun вне форума Ответить с цитированием
Старый 22.01.2011, 01:24   #9
Dayman
Форумчанин
 
Аватар для Dayman
 
Регистрация: 12.01.2011
Сообщений: 186
По умолчанию

Значит один голос за второй пункт. Парсеров правда много будет, так что получиться что-то вроде:
GUI вызывает Core, Core вызывает парсер.

Цитата:
Сообщение от Obey-Kun Посмотреть сообщение
Тогда я бы так сделал:
Кстати. У меня программа разбита на ядро и гуй, но я Qt везде использую, тем более ядро я разрабатываю вместе с гуём. В ядре я Qt использую как минимум для использования Qt'шных контейнеров. Правда, собирать в отдельную библиотеку ядро не собираюсь, это ни к чему, хотя это и возможно.
У меня так не получится. GUI должен быть заменяемым, т.к. планируется порт под CE. Единственное, что ему позволяется, это иметь свою структуру конфиг файла в модуле типов данных и парсер к этой структуре.
Lingua c++ non penis caninus est.
Dayman вне форума Ответить с цитированием
Старый 22.01.2011, 01:27   #10
Obey-Kun
Линуксоид
Участник клуба
 
Аватар для Obey-Kun
 
Регистрация: 31.07.2009
Сообщений: 1,403
По умолчанию

Но я не правда в последней инстанции. Потому что самому такое делать пока не приходилось. Может, тут скажут чего полезного: http://www.linux.org.ru/forum/development/5820291 (уверен, что скажут, т.к. там действительно много людей, которые секут в больших проектах).

И Qt для Windows CE есть. http://qt.nokia.com/products/platfor...or-windows-ce/
Мало того, писать мобильные приложения на кутях — сказка. Недаром их Nokia купила.
Я схожу с ума или это глючит реальность?
Jabber ID: obey@obey.su
Obey-Kun вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обработка ошибок kardinal94 Общие вопросы Delphi 2 21.11.2010 20:23
Обработка ошибок Liones БД в Delphi 12 04.12.2008 07:22
Обработка ошибок Ivanich JavaScript, Ajax 1 24.04.2008 22:49
Обработка ошибок в Delphi 7 Наташкин БД в Delphi 3 21.12.2007 22:07
Обработка ошибок. Serviceprofi Помощь студентам 7 19.11.2007 15:12