2011-07-05 99 views
10

使用C#或Java时,我用来创建包含其他例外类的成员的例外类。例如:C++中例外情况下的例外

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++的例子,我找不到任何(也许我没有寻找正确的条款,你可以看到这个问题的标题不是很花哨)。

无论如何,在C++中这样做的正确方法是什么?是将内部异常存储为指针还是引用? (我想我可能需要一个指针,所以当它是第一个异常时它可以为空)。当我抛出异常时,它应该是与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

在C++中不能有多个异常。如果在捕获到当前异常之前抛出一个新的异常,则程序终止(更确切地说,调用std :: terminate') –

+0

@Gene:这是重新抛出的一种变体,其中现有的异常塞入新的异常。没有垃圾收集可能不可行。 –

+0

@Ben Voigt:如果没有垃圾收集的话,如果它不是很难记得什么时候异常被调用的析构函数的话,那么可能是可行的。 –

回答

0

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

+0

'MyException'类成员的使用方式如下: 1.我发现抛出的异常 2.我用另一个更具体的消息实例化**另一个异常,并将'ex'属性设置为1 中捕获到的异常3.抛出新的异常。 虽然这是一个很好的教程,你发给我的。 – Renan

+0

它看起来像你想保留它作为参考,对吧?为什么它不是'Exception'实例呢?此外,如果您只需要一个反向引用来保留原始异常,为什么不简单地叠加跟踪消息并抛出原始异常呢?可能在构造函数中?这对我来说更有理由。我的2美分 – shinkou

21

没有正确的方法来处理C++ 03中的标准异常,因为它们被设计为多态使用,但不能被克隆。所以如果你赶上std::exception const& e可能存储副本,但这会导致切片,失去所有有用的信息。您应该而不是存储指向或异常的引用,因为只要离开catch子句(假定您不重新抛出原始异常),其生命周期就会结束。

如果您知道可以抛出并测试它们的每种类型,但是这不是一个好设计(即它会破坏多态性),则可以避开此限制。编写一个可以克隆的基本异常类更有意义,并捕获它。但是,如果您发现来自其他人代码的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_exceptiontypedef也应该是库的一部分;同时你自己编写它很容易。

不要期待魔术:boost::current_exception只有在使用投掷位置boost::enable_current_exception时,“捕捉”活动的异常(精细打印:或其克隆)才会罚款。 (在功能上,这是使用可克隆的基本异常类的道德等同物)。如果没有,它不会失败,但一些信息可能会丢失。


作为最后一点,要知道Boost.Exception的设计被C++ 0x采用。因此,正确以下存储活动例外,没有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()); 
} 
+0

感谢抬起头,C++ 0x中不断令人惊讶的我:) –

1

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

+0

而且你必须确保只有指向同一个基类被抛出,因为这并不表现多态。 –

+0

@Luc:那肯定是一个缺点,不是吗? –

+0

那么,鉴于'std :: unique_ptr'是C++ 0x,我认为有更好的选择。 –