JavaScript:
function i(){ i(); }
i();
<час> C++ Используя указатель функции:
int main(){
int (*f)() = &main;
f();
}
Я бы воздержался от разработки иерархии исключений, отличной от вашей библиотеки. По возможности используйте иерархию std :: exception
, а всегда извлекайте исключения из чего-то в этой иерархии. Вы можете прочитать раздел об исключениях в разделе часто задаваемых вопросов по 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;
};
Идея состоит в том, чтобы сделать конструктор копирования защищенным и заставить пользователей вызовите Класс (аргументы). Raise ()
вместо throw Class (args)
. Это позволяет вам генерировать полиморфно привязанное исключение, которое ваши пользователи могут перехватить только по ссылке. Любая попытка поймать по значению должна быть встречена красивым предупреждением компилятора. Что-то вроде:
foo.cpp: 59: error: 'bar_exception :: bar_exception (const bar_exception &)' защищено
foo.cpp: 103: error: в этом контексте
Конечно, все это происходит price, поскольку вы больше не можете использовать throw
явно, иначе вы получите аналогичное предупреждение компилятора:
foo.cpp: в функции 'void h ()':
foo.cpp: 31 : error: 'foo_exception :: foo_exception (const foo_exception &)' защищен
foo.cpp: 93: error: в этом контексте
foo.cpp: 31: error: 'foo_exception :: foo_exception (const foo_exception &)' защищен
foo.cpp: 93: ошибка: в этом контексте
В целом, я бы полагался на стандарты кодирования и документацию, в которой говорится, что вы всегда должны ловить по ссылке. Убедитесь, что ваша библиотека перехватывает исключения, которые она обрабатывает по ссылке, и генерирует новые объекты (например, throw Class (constructorArgs)
или throw;
). Я ожидал бы, что другие программисты на C ++ будут обладать такими же знаниями, но добавьте примечание к любой документации, чтобы быть уверенным.
У вашего исключения должен быть общедоступный конструктор копирования. Компилятор должен иметь возможность копировать его, чтобы обработка исключений работала.
Решение вашей проблемы состоит в том, чтобы вместо этого всегда выполнять поиск по ссылке:
try {
// some code...
throw MyException("lp0 is on fire!");
} catch (MyException const &ex) {
// handle exception
}
( const
-ness не является обязательным, но я всегда вставляйте его, потому что редко нужно изменять объект исключения.)
Я бы сказал, что не следует использовать какой-либо встроенный код исключений C ++. Если у вас должны быть исключения, создайте собственное с нуля. Это единственный способ убедиться, что они будут вести себя одинаково, не говоря уже о том, чтобы быть реализованными аналогичным образом, и, говоря прямо, реализация исключений в C ++ некомпетентна.
Ответ Томаса правильный, но я Я также хотел бы предложить вам не тратить свое время на «проектирование иерархии исключений». Разработка иерархий классов - особенно плохая идея, особенно когда вы можете просто вывести пару (и не больше) новых типов исключений из классов исключений Standard C ++.