С++ exception: throwing std::string
Я хотел бы создать исключение, когда мои методы С++ сталкиваются с чем-то странным и не могут восстановиться. Можно ли сбросить указатель std::string
?
Вот что я с нетерпением ждал:
void Foo::Bar() {
if(!QueryPerformanceTimer(&m_baz)) {
throw new std::string("it 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;
}
}
Ответы
Ответ 1
Да. std::exception
является базовым классом исключений в стандартной библиотеке С++. Возможно, вы захотите избежать использования строк в качестве классов исключений, поскольку они сами могут генерировать исключение во время использования. Если это произойдет, тогда где вы будете?
boost имеет отличный документ о хорошем стиле для исключений и обработки ошибок. Это стоит прочитать.
Ответ 2
Несколько принципов:
-
У вас есть базовый класс 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 the end of the world!");
}
}
void Foo::Caller(){
try{
this->Bar();// should throw
}catch(MyException& caught){
std::cout<<"Got "<<caught.what()<<std::endl;
}
}
Ответ 3
Все эти работы:
#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 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. Обратите внимание, что в наименее предпочтительном варианте вам необходимо явно освободить память.
Ответ 4
Это работает, но я бы не сделал этого, если бы был вами. Кажется, вы не удаляете данные кучи, когда закончите, а это значит, что вы создали утечку памяти. Компилятор С++ заботится о том, чтобы данные исключений сохранялись в живых, даже когда стек выскочил, поэтому не чувствуйте, что вам нужно использовать кучу.
Кстати, бросать std::string
не лучший подход для начала. У вас будет гораздо больше гибкости, если вы используете простой объект-обертку. Он может просто инкапсулировать string
на данный момент, но, возможно, в будущем вы захотите включить другую информацию, например, некоторые данные, которые вызвали исключение, или, может быть, номер строки (очень распространенный). Вы не хотите изменять всю свою обработку исключений в каждом месте в своей базе кода, поэтому переходите на большую дорогу и не бросайте необработанные объекты.
Ответ 5
В дополнение к тому, что, вероятно, выкидываете что-то, полученное из std:: exception, вы должны бросать анонимные временные файлы и вызывать по ссылке:
void Foo::Bar(){
if(!QueryPerformanceTimer(&m_baz)){
throw std::string("it 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;
}
}
- Вы должны бросить анонимный
временно, поэтому компилятор
с временем жизни объекта
вы бросаете - если вы бросаете
что-то новое с кучи,
кто-то еще должен освободить
вещь.
- Вы должны улавливать ссылки на
предотвращать нарезку объектов
.
Подробнее см. Meyer "Эффективный С++ - 3-е издание" или посетите https://www.securecoding.cert.org/.../ERR02-A. + броском + анонимными + +, и временные конструкции + Catch + на + ссылки
Ответ 6
Самый простой способ выбросить исключение в С++:
#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 support team for more information.
Ответ 7
Хотя этот вопрос довольно старый и уже был дан ответ, я просто хочу добавить примечание о том, как выполнять правильную обработку исключений в С++ 11:
Использование этих, по моему мнению, приводит к более чистому дизайну исключений и делает ненужным создание иерархии классов исключений.
Обратите внимание, что это позволяет получать обратную трассировку на свои исключения внутри вашего кода без необходимости отладки или громоздкого ведения журнала. Описано здесь в 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"