尝试使用RAII捕获?

时间:2011-02-10 07:25:31

标签: c++ exception-handling

我有一个类,它有一些像下面这样的方法(还有更多):

    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;
        }
    }

Q1:建议使用这样的例外吗? (在每个功能中)。我不熟悉使用异常,所以我不确定。

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 个答案:

答案 0 :(得分:6)

  

Q1:建议使用这样的例外吗? (在每个功能中)。我不熟悉使用异常,所以我不确定。

没有特别的问题,但没有特别的原因,除非你计划丰富异常信息,区分一些ios_base ::失败函数与其他等等。你只想让每个函数更大/更复杂如果它其他更小/更简单的东西。

  

Q2:如果Q1的答案是肯定的,我可以做这样的事情来消除冗余吗?

您可以使用宏来为您生成try / catch块。如果你按照你的建议行事,那么在处理异常时会调用析构函数:如果你再次尝试抛出,那么将调用terminate()。有关详细信息,请查看C ++ Lite常见问题解答:http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9

答案 1 :(得分:3)

回答Q1:meh ......

回答Q2:nope,析构函数体将始终运行,不会收到任何异常数据。你不能用这种方式替换一个catch子句。

即使你可以,也不会属于RAII这个词。它有点类似于RAII,因为使用自动内存规则会导致某些事情发生,但就是这样。 (A)所需的(R)资源在哪里,例如......

答案 2 :(得分:3)

广告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 :(得分:0)

包装异常就是你应该做的事情,如果你确定你需要 - 它通常不是很有用。

您无法从析构函数中捕获异常,但您可以执行以下操作:

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();
  }
}

这里的重新抛出代码很短,所以可能不值得。如果异常处理代码很长,那么它可能是有益的。