Я хотел бы вызвать исключение, когда мои методы C ++ обнаруживают что-то странное и не могут восстановиться. Можно ли бросать std::string
указатель?
Вот что я с нетерпением ждал:
void Foo::Bar() {
if(!QueryPerformanceTimer(&m_baz)) {
throw new std::string("it's the end of the world!");
}
}
void Foo::Caller() {
try {
this->Bar(); // should throw
}
catch(std::string *caught) { // not quite sure the syntax is OK here...
std::cout << "Got " << caught << std::endl;
}
}
Ответы:
Да.
std::exception
является базовым классом исключения в стандартной библиотеке C ++. Возможно, вы захотите избежать использования строк в качестве классов исключений, потому что они сами могут вызывать исключение во время использования. Если это произойдет, то где вы будете?У boost есть отличный документ о хорошем стиле для исключений и обработки ошибок. Стоит прочитать.
источник
Несколько принципов:
у вас есть базовый класс std :: exception, исключения должны быть производными от него. Таким образом, у общего обработчика исключений все еще есть некоторая информация.
Не бросайте указатели, а объект, таким образом память обрабатывается за вас.
Пример:
struct MyException : public std::exception { std::string s; MyException(std::string ss) : s(ss) {} ~MyException() throw () {} // Updated const char* what() const throw() { return s.c_str(); } };
А затем используйте его в своем коде:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw MyException("it's the end of the world!"); } } void Foo::Caller(){ try{ this->Bar();// should throw }catch(MyException& caught){ std::cout<<"Got "<<caught.what()<<std::endl; } }
источник
Все это работает:
#include <iostream> using namespace std; //Good, because manual memory management isn't needed and this uses //less heap memory (or no heap memory) so this is safer if //used in a low memory situation void f() { throw string("foo"); } //Valid, but avoid manual memory management if there's no reason to use it void g() { throw new string("foo"); } //Best. Just a pointer to a string literal, so no allocation is needed, //saving on cleanup, and removing a chance for an allocation to fail. void h() { throw "foo"; } int main() { try { f(); } catch (string s) { cout << s << endl; } try { g(); } catch (string* s) { cout << *s << endl; delete s; } try { h(); } catch (const char* s) { cout << s << endl; } return 0; }
Вы должны предпочесть h вместо f вместо g. Обратите внимание, что в наименее предпочтительном варианте вам нужно явно освободить память.
источник
const char
указателя на локальную переменную не является ошибкой? Да, конечно, я знаю, что компилятор поместит c-строку в немодифицированный раздел, который не изменит адрес до запуска приложения. Но это не определено; более того, что было бы, если бы этот код был в библиотеке, которая исчезла сразу после выдачи ошибки? Кстати, я тоже много такого плохого натворил в своем проекте, я всего лишь студент. Но я должен был подумать об этом ...Это работает, но на вашем месте я бы этого не сделал. Похоже, вы не удаляете эти данные из кучи, когда закончите, а это значит, что вы создали утечку памяти. Компилятор C ++ заботится о том, чтобы данные об исключениях сохранялись даже при извлечении стека, поэтому не думайте, что вам нужно использовать кучу.
Между прочим, бросание
std::string
- не лучший подход для начала. В будущем у вас будет гораздо больше гибкости, если вы будете использовать простой объект-оболочку. На данный момент он может просто инкапсулировать astring
, но, возможно, в будущем вы захотите включить другую информацию, например, некоторые данные, которые вызвали исключение, или, возможно, номер строки (очень часто). Вы не хотите изменять всю обработку исключений в каждом месте своей кодовой базы, поэтому идите по дороге прямо сейчас и не бросайте необработанные объекты.источник
В дополнение к вероятному выбрасыванию чего-то, производного от std :: exception, вы должны генерировать анонимные временные объекты и ловить по ссылке:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw std::string("it's the end of the world!"); } } void Foo:Caller(){ try{ this->Bar();// should throw }catch(std::string& caught){ // not quite sure the syntax is ok here... std::cout<<"Got "<<caught<<std::endl; } }
.
См. Подробности в «Эффективном C ++ - 3-е издание» Мейера или посетите https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
источник
Самый простой способ выбросить исключение в C ++:
#include <iostream> using namespace std; void purturb(){ throw "Cannot purturb at this time."; } int main() { try{ purturb(); } catch(const char* msg){ cout << "We caught a message: " << msg << endl; } cout << "done"; return 0; }
Это печатает:
We caught a message: Cannot purturb at this time. done
Если вы поймаете сгенерированное исключение, исключение будет сохранено, и программа будет продолжена. Если вы не поймаете исключение, значит программа существует и печатает:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
источник
catch (std::exception&)
не пойму.Хотя этот вопрос довольно старый и на него уже был дан ответ, я просто хочу добавить примечание о том, как правильно обрабатывать исключения в C ++ 11. :
Использование
std::nested_exception
иstd::throw_with_nested
Их использование, на мой взгляд, приводит к более чистому дизайну исключений и делает ненужным создание иерархии классов исключений.
Обратите внимание, что это позволяет вам отслеживать исключения внутри вашего кода без необходимости использования отладчика или громоздкого ведения журнала. Это описано на StackOverflow здесь и здесь , как написать правильный обработчик исключений, который будет повторно генерировать вложенные исключения.
Поскольку вы можете сделать это с любым производным классом исключений, вы можете добавить много информации в такую трассировку! Вы также можете взглянуть на мою MWE на GitHub , где трассировка будет выглядеть примерно так:
Library API: Exception caught in function 'api_function' Backtrace: ~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed ~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
источник