Что такое хороший дизайн для набора классов исключений? Я вижу всевозможные вещи вокруг того, что классы исключений должны и не должны делать, но не простой дизайн, который прост в использовании и расширении, что делает эти вещи.
- Классы исключений не должны генерировать исключения, так как это может привести к прекращению процесса без каких-либо ошибок для регистрации ошибки и т.д.
- Должна быть доступна удобная строка, предпочтительнее локализованная на их языке, чтобы было что-то сказать им до того, как приложение закончит сам, если оно не сможет восстановить ошибку.
- Должна быть доступна возможность добавлять информацию по мере удаления пакета, например, если синтаксический анализатор XML не может проанализировать входной поток, чтобы добавить, что источник был из файла, или по сети и т.д.
- Обработчики исключений нуждаются в легком доступе к информации, необходимой им для обработки исключения.
- Запись форматированной информации об исключении в файл журнала (на английском языке, поэтому никаких переводов здесь нет).
Получение 1 и 4 для совместной работы - самая большая проблема, с которой я сталкиваюсь, поскольку любые методы форматирования и вывода файлов могут потенциально потерпеть неудачу.
EDIT: Поэтому, рассмотрев классы исключений в нескольких классах, а также в вопросе Нила, связанном с ним, кажется, что обычной практикой является просто игнорировать пункт 1 (и, следовательно, рекомендации по усилению), что представляется мне довольно плохой идеей.
В любом случае я думал, что id также публикует класс исключений, о котором я думаю использовать.
class Exception : public std::exception
{
public:
//enum for each exception type, which can also be used to determin
//exception class, useful for logging or other localisation methods
//for generating a message of some sort.
enum ExceptionType
{
//shouldnt ever be thrown
UNKNOWN_EXCEPTION = 0,
//same as above but has a string that may provide some info
UNKNOWN_EXCEPTION_STR,
//eg file not found
FILE_OPEN_ERROR,
//lexical cast type error
TYPE_PARSE_ERROR,
//NOTE: in many cases functions only check and throw this in debug
INVALID_ARG,
//an error occured while trying to parse data from a file
FILE_PARSE_ERROR,
}
virtual ExceptionType getExceptionType()const throw()
{
return UNKNOWN_EXCEPTION;
}
virtual const char* what()throw(){return "UNKNOWN_EXCEPTION";}
};
class FileOpenError : public Exception
{
public:
enum Reason
{
FILE_NOT_FOUND,
LOCKED,
DOES_NOT_EXIST,
ACCESS_DENIED
};
FileOpenError(Reason reason, const char *file, const char *dir)throw();
Reason getReason()const throw();
const char* getFile()const throw();
const char* getDir ()const throw();
private:
Reason reason;
static const unsigned FILE_LEN = 256;
static const unsigned DIR_LEN = 256;
char file[FILE_LEN], dir[DIR_LEN];
};
Точка 1 адресована, поскольку все строки обрабатываются путем копирования во внутренний буфер фиксированного размера (при необходимости усекается, но всегда завершается нуль).
Хотя это не относится к пункту 3, однако я думаю, что этот момент, скорее всего, ограничен в ограниченном использовании в реальном мире, и, скорее всего, его можно было бы устранить, если при необходимости добавить новое исключение.