Я хотел бы избежать разработки иерархии исключений, отдельной для вашей библиотеки. Максимально используйте иерархию std::exception
, и всегда выводит ваши исключения из чего-то внутри этой иерархии. Возможно, вы захотите прочитать часть исключений в FAQ C ++ Маршалла Клайна - прочитать FAQ 17,6 , 17,9 , 17,10 и В частности, 17.12 .
Что касается , "заставляющего пользователей ловить по ссылке" , я не знаю, как это сделать. Единственный способ, которым я придумал через час или около того игры (это воскресенье днем), основан на полиморфном броске :
class foo_exception {
public:
explicit foo_exception(std::string msg_): m_msg(msg_) {}
virtual ~foo_exception() {}
virtual void raise() { throw *this; }
virtual std::string const& msg() const { return m_msg; }
protected:
foo_exception(foo_exception const& other): m_msg(other.m_msg) {}
private:
std::string m_msg;
};
class bar_exception: public foo_exception {
public:
explicit bar_exception(std::string msg_):
foo_exception(msg_), m_error_number(errno) {}
virtual void raise() { throw *this; }
int error_number() const { return m_error_number; }
protected:
bar_exception(bar_exception const& other):
foo_exception(other), m_error_number(other.m_error_number) {}
private:
int m_error_number;
};
Идея состоит в том, чтобы сделать конструктор копирования защищенным и заставить пользователей вызывать Class(args).raise()
вместо throw Class(args)
. Это позволяет создавать исключение с полиморфной привязкой, которое ваши пользователи могут отлавливать только по ссылке. Любая попытка поймать по значению должна приветствоваться хорошим предупреждением компилятора. Что-то вроде:
foo.cpp: 59: ошибка: «bar_exception :: bar_exception (const bar_exception &)» защищена
foo.cpp: 103: ошибка: в этом контексте
Конечно, все это имеет свою цену, поскольку вы больше не можете явно использовать throw
, иначе вас встретит аналогичное предупреждение компилятора:
foo.cpp: в функции void h () ’:
foo.cpp: 31: ошибка: «foo_exception :: foo_exception (const foo_exception &)» защищена
foo.cpp: 93: ошибка: в этом контексте
foo.cpp: 31: ошибка: «foo_exception :: foo_exception (const foo_exception &)» защищена
foo.cpp: 93: ошибка: в этом контексте
В целом, я бы полагался на стандарты кодирования и документацию, в которой указано, что вы всегда должны ловить ссылки. Убедитесь, что ваша библиотека перехватывает исключения, которые она обрабатывает по ссылке, и генерирует свежие объекты (например, throw Class(constructorArgs)
или throw;
). Я ожидал бы, что другие программисты C ++ будут иметь те же знания - но для большей уверенности добавлю примечание к любой документации.