Подтвердить что ты не робот

С++ 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;
    }
}
4b9b3361

Ответ 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:

Используйте 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"