C ++中异常内部的异常

时间:2011-07-05 02:27:53

标签: c++ exception

使用C#或Java时,我曾经创建了包含其他异常作为类成员的异常类。例如:

public class MyException : Exception {
    private MyException ex;
    private String message;

    public String what() {
        return this.message;
    }

    public String stack() {
        if(ex != null) {
            StringBuilder s;
            s.append(this.what());
            s.append(this.ex.stack());
            return s.toString();
        }

        return this.what();
    }
}

我一直在寻找同一主题的例子,但是对于C ++而言我找不到(也许我没有找到正确的术语,因为你可以看到这个问题的标题不是很花哨)。 / p>

无论如何,在C ++中这样做的正确方法是什么?它是将内部异常存储为指针还是引用? (我想我可能需要一个指针,所以当它是第一个异常时它可以为null)。当我引发异常时,它应该是用new创建的指针吗?

编辑:也许我写的有点令人困惑或者不是一个众所周知的(接受的)编程实践。因此,我将指定我打算如何将此类与片段一起使用:

 try {
     // Code that throws an exception of type MyException
 } catch(MyException ex) {
     MyException another = new MyException();
     another.setEx(ex);
     another.setMessage("A message that explains where the other exception was caught and on what conditions");

     throw another;
 }

3 个答案:

答案 0 :(得分:21)

使用C ++ 03中的标准异常没有正确的方法,因为它们被设计为多态使用但无法克隆。因此,如果您抓住std::exception const& e可以存储副本,但这会导致切片,丢失所有有用信息。您应该存储指针或对该异常的引用,因为它的生命周期将在离开catch子句后立即结束(假设您不重新抛出原始异常)。 / p>

如果您知道可以抛出的每种类型并测试它们,但是这不是一个好的设计(即它颠覆了多态性),您可以解决这个限制。编写一个可以克隆的自己的基本异常类更有意义,并抓住它。如果你抓住来自其他人代码的std::exception,你仍然会遇到问题。

此时我不得不提及Boost.Exception。它使您可以轻松编写自己的异常层次结构并提供各种实用程序,其中包括boost::exception_ptr。然后你可以这样做:

typedef boost::error_info<struct tag_nested_exception, boost::exception_ptr>
    nested_exception;

// ...
catch(...) {
    // better: use BOOST_THROW_EXCEPTION
    throw your_exception_type() << nested_exception( boost::current_exception() );
}

这非常有用,boost::diagnostic_info支持它并将为您显示嵌套异常(它没有记录)。甚至有人建议这个nested_exception typedef也应该是图书馆的一部分;与此同时,你自己写的很容易。

不要指望魔术:boost::current_exception'捕获'活动异常(精细打印:或它的克隆)只有在抛出站点使用boost::enable_current_exception时才会很好。 (从功能上讲,这是使用可以克隆的基本异常类的道德等价物)。如果没有,它不会失败,但某些信息可能会丢失。


最后请注意,知道C ++ 0x采用了Boost.Exception的设计。因此,以下正确存储活动异常,没有boost::current_exception警告,因为它有语言支持:

// you can still use Boost.Exception:
typedef boost::error_info<struct tag_nested_exception, std::exception_ptr>
    nested_exception;

// ...
catch(...) {
    // e has type std::exception_ptr
    auto e = std::current_exception();
    // internally store the std::exception_ptr
    throw your_exception_type(e);

    // or with Boost
    BOOST_THROW_EXCEPTION( your_exception_type() << nested_exception(e) );
}

还有一种std::nested_exception类型可以很容易地使用,如下所示:

catch(...) {
    // throws an unspecified type derived from your_exception_type
    // and std::nested_exception
    std::throw_with_nested(your_exception_type());
}

答案 1 :(得分:1)

我猜你可以抛出一个unique_ptr<some_exception>,然后让inner_exception另一个unique_ptr获得所有权。

答案 2 :(得分:0)

如果您的类不是以单例模式设计的,我认为我们不需要Java / C#/ C ++中的类实例属性(即ex)。此外,here是您可能想要查看的教程。