попробовать поймать с помощью RAII? - PullRequest
4 голосов
/ 10 февраля 2011

У меня есть класс, который имеет несколько методов, таких как следующим (и более):

    template<class T>
    Logpp& operator<<(T const& obj)
    {
        *p_Stream << obj ;
        return *this ;
    }

    Logpp& operator<<(char const* zString)
    {
        *p_Stream << zString ;
        return *this ;
    }

    Logpp& operator<<(std::ostream& (*manip)(std::ostream&))
    {
        *p_Stream << manip;
        return *this ;
    }

Я хочу заключить тело функции в блок try catch вида:

    Logpp& operator<<(std::ostream& (*manip)(std::ostream&))
    {
        try
        {
            *p_Stream << manip;
            return *this;
        }
        catch(ios_base::failure& e)
        {
            //MyException has a stringstream inside and can use operator<<
            throw MyException("IO failure writing to log file : ") << e.what() << endl;
        }
    }

В1: Желательно ли использовать подобные исключения? (В каждой функции). Я не знаком с использованием исключений, поэтому я не уверен.

Q2: Если ответ на вопрос Q1 положительный, могу ли я сделать что-то подобное для устранения избыточности?

    Logpp& operator<<(std::ostream& (*manip)(std::ostream&))
    {
        Catch<ios_base::failure> tc();
        try
        {
            *p_Stream << manip;
            return *this;
        }
        //destructor of tc will be written to catch the template exception type and rethrow as a MyException.
    }

Ответы [ 4 ]

6 голосов
/ 10 февраля 2011

В1: Желательно ли использовать подобные исключения? (В каждой функции). Я не знаком с использованием исключений, поэтому я не уверен.

Нет особой проблемы, но нет особой причины, если только вы не планируете обогащать информацию об исключении, отличать некоторые функции ios_base :: fault от других и т. Д. Вы хотите сделать каждую функцию больше / сложнее, если она делает что-то еще меньше / проще.

Q2: Если ответ на вопрос Q1 положительный, могу ли я сделать что-то подобное для устранения избыточности?

Вы можете использовать макрос для генерации блоков try / catch. Если вы сделаете то, что предлагаете, деструктор будет вызван во время обработки исключения: если вы попытаетесь бросить снова, будет вызван terminate(). Подробности см. В FAQ по C ++ Lite: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9

3 голосов
/ 10 февраля 2011

Объявление Q1:

Я бы немного порекомендовал против этого. Обтекание исключений должно быть сделано, когда вызывающая сторона, в конечном итоге обрабатывающая исключение, не должна знать о внутренних деталях, и исходное исключение не будет иметь для него смысла. Но для operator<< бросок std::ios_base::failure имеет смысл, поэтому я бы не стал здесь переносить.

Объявление Q2:

Нет, но вы могли бы сделать что-то вроде:

Logpp& do_output(std::ostream& (*manip)(std::ostream&))
{
    *p_Stream << manip;
    return *this;
}

Logpp& operator<<(std::ostream& (*manip)(std::ostream&))
{
    return wrap_exception(&Logpp::do_output, this, manip);
}

(возможно, немного проще, используя связывание из TR1 / Boost как

    return wrap_exception(bind(&Logpp::do_output, this, manip));
3 голосов
/ 10 февраля 2011

Ответ на вопрос 1: Мех ...

Ответ на вопрос 2: нет, тело деструктора всегда будет работать и не получит никаких данных об исключениях. Вы не можете заменить предложение catch таким образом.

Даже если бы вы могли, это не подпадает под термин RAII. Это похоже на RAII в том смысле, что использование автоматических правил памяти используется для того, чтобы вызвать определенные вещи, но это все. Где (R) источник, который (A) запрашивается, например ...

0 голосов
/ 10 февраля 2011

Обтекание исключений - это то, что вам следует делать, только если вы уверены, что вам это нужно - обычно это бесполезно.

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

void handleCurrentException()
{
  try { throw; } // rethrow currently active exception
  catch (ios_base::failure& e)
  {
    // exception handling/rethrowing code
  }
}

Logpp& operator<<(std::ostream& (*manip)(std::ostream&))
{
  try
  {
    *p_Stream << manip;
    return *this;
  }
  catch(...)
  {
    handleCurrentException();
  }
}

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

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