0

Создание пользовательских исключений в C++

11

Я изучаю C++ и сталкиваюсь с проблемой, когда пытаюсь создать собственное исключение и выбросить его в Linux.

Я создал небольшой тестовый проект для проверки своей реализации, и ниже приведен заголовочный файл моего класса исключения.

class TestClass : public std::runtime_error
{
public:
    TestClass(char const* const message) throw();
    virtual char const* what() const throw();
};

Исходный файл класса исключения выглядит следующим образом:

using namespace std;

TestClass::TestClass(char const* const message) throw()
    : std::runtime_error(message)
{

}

char const * TestClass::what() const throw()
{
    return exception::what();
}

В моем основном приложении я вызываю функцию, которая выбрасывает мое исключение, и перехватываю его в блоке try/catch следующим образом:

void runAFunctionAndthrow();

/*
 * 
 */
int main(int argc, char** argv) {
    try
    {
        cout << "About to call function" << endl;
        runAFunctionAndthrow();
    }
    catch (TestClass ex)
    {
        cout << "Exception Caught: " << ex.what() << endl;
    }

    return 0;
}

void runAFunctionAndthrow()
{
    cout << "going to run now. oh dear I need to throw an exception" << endl;

    stringstream logstream;
    logstream << "This is my exception error. :(";
    throw TestClass(logstream.str().c_str());
}

Когда я запускаю программу, я ожидаю получить следующий вывод:

About to call function
going to run now. oh dear I need to throw an exception
Exception Caught: This is my exception error. :(

Однако вместо этого я получаю:

About to call function
going to run now. oh dear I need to throw an exception
Exception Caught: std::exception

Обратите внимание на последнюю строку: вместо моего фактического сообщения об исключении "This is my exception error. 😦" выводится std::exception.

Почему так происходит? На Windows все работает нормально, а на Linux — нет.

Судя по различным постам, я сделал все правильно, так что что же я упустил?

2 ответ(ов)

0

Первое, большинство информации о данном вопросе уже было предоставлено Самом Варшавчиком. Однако я хотел бы добавить одно важное замечание. При выбросе и перехвате исключений хорошо следовать правилу:

"Выбрасывай по значению, перехватывай по ссылке"

Ваш код для выброса исключения выглядит корректно:

void runAFunctionAndthrow()
{
    cout << "Сейчас буду выполняться. Ой, мне нужно выбросить исключение" << endl;
    stringstream logstream;
    logstream << "Это мое исключение с ошибкой. :(";
    throw TestClass(logstream.str().c_str());
}

Здесь используется неявное преобразование к TestClass, после чего объект передается по значению.

Ключевой момент этого правила заключается в минимизации выделения памяти и обработки между различными стековыми рамками.

Однако ваш обработчик исключения не следует этому правилу, так как вы перехватываете исключение по значению:

catch (TestClass ex)
{
    cout << "Исключение перехвачено: " << ex.what() << endl;
}

Правильный вариант перехвата должен выглядеть так: (const TestClass& ex).

Ключевым моментом этого правила является неявное преобразование между базовым и производным классами.

0

Самый краткий способ создать пользовательское исключение начиная с C++11 — это использовать конструктор родителя std::runtime_error:

struct my_exception : std::runtime_error {
    using std::runtime_error::runtime_error;
};

Это позволит унаследовать все конструкторы std::runtime_error, что покрывает большинство потребностей в обработке исключений.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь