Реализация класса исключений в C ++ - PullRequest
4 голосов
/ 10 сентября 2010

Итак, я пытаюсь написать простой базовый класс Exception для C ++, основанный на классе Java Exception. Я уверен, что уже есть отличные библиотеки, но я делаю это для практики, а не для производственного кода, и мне любопытно, и я всегда хочу учиться Одна из вещей, которую делает Исключение Java, которую я хотел бы также реализовать, - это понятие «причина». В Java новое исключение с причиной выглядит так:

Exception cause = new Exception();
Exception newExcept = new Exception(cause);

Однако в C ++ передача исключения в качестве аргумента конструктору - это то, как вызывается конструктор копирования. Таким образом, существует концептуальное несоответствие между копированием исключения и созданием нового исключения с причиной. Это не проблема в Java, очевидно.

Полагаю, мне просто интересно, как лучше всего с этим справиться. У меня было несколько идей:

  • Дифференцировать с фиктивной переменной
  • Просто создайте новое исключение и вызовите метод setCause ()
  • Что-то вроде конструктора копирования - Exception(Exception &), а конструктор с причиной - Exception(Exception *)

Спасибо

Ответы [ 4 ]

5 голосов
/ 10 сентября 2010

Исключение - при размещении в стеке (я бы настоятельно рекомендовал это) - освобождается после предложения catch. Поэтому вам нужно создать копию «внутреннего» исключения во вновь созданном исключении. Если вы поймаете базовый класс вашего исключения, он потеряет свой правильный тип, если вы не передадите в исключение метод клонирования.

#include <string>
#include <exception>

class MyBaseException : public std::exception
{
public:
    MyBaseException(const std::string& what = std::string("MyBaseException"))
        : m_BaseException(0), m_What(what) {}  //Constructor without inner exception

    MyBaseException(const MyBaseException& innerException, const std::string& what = std::string("MyBaseException"))
        : m_BaseException(innerException.clone()), m_What(what) {}  //Constructor with inner exception

    template <class T>  // valid for all subclasses of std::exception
    MyBaseException(const T& innerException, const std::string& what = std::string("MyBaseException"))
        : m_BaseException(new T(innerException)), m_What(what) {}

    virtual ~MyBaseException() throw()
        { if(m_BaseException) { delete m_BaseException; } } //don't forget to free the copy of the inner exception
    const std::exception* base_exception() { return m_BaseException; }
    virtual const char* what() const throw()
        { return m_What.c_str(); } //add formated output for your inner exception here
private:
    const std::exception* m_BaseException;
    const std::string m_What;
    virtual const std::exception* clone() const
        { return new MyBaseException(); } // do what ever is necesary to copy yourselve
};

int main(int argc, char *argv[])
{
    try {
        try {
            throw std::exception();
        }
        catch(const std::exception& e) {
            throw MyBaseException(e, "bad");
        }
    }
    catch (const MyBaseException& e) {
        throw MyBaseException(e, "even worse");
    }
    //throw MyBaseException(1, "will not compile");
}
2 голосов
/ 10 сентября 2010

Вы можете использовать заводскую модель:

Exception cause = Exception.Create();
Exception newExcept = Exception.Create( Exception cause );
1 голос
/ 10 сентября 2010

Просто добавьте строку с причиной исключения к текущему исключению:

try
{
    throw std::runtime_error("Failed to work");
}
catch(std::exception const& e)
{
    // New exception (add origianl exception text).
    throw std::runtime_error(std::string("We were doing poobar when: ") + e.what());
}
0 голосов
/ 10 сентября 2010

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

Решение состоит в том, чтобы создать библиотечное исключение (или как вы хотите его назвать)

class library_exception: public std::exception
{
 ...
 public:
   library_exception(const  std::exception &e)
 ...
}
...
catch(const std::exception &e)
{
  ...
  throw library_exception(e);
}

В разных классах не вызывается конструктор копирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...