C++中用于定义异常类和抛出异常的标准方法

ip8*_*p84 12 c++ standards exception instance throw

我想构建一个具有函数的类,这些函数可能会抛出我想要在使用它时捕获的异常.我从标准异常类继承my_exception.我实现了what()函数,以便它返回一个存储在私有字符串变量中的字符串

我认为最好将异常定义为嵌套类,就像在iosream库中使用ios_base :: failure一样.

我不太确定的是,我应该在哪里以及如何定义my_excpetion的对象.我希望我能看到iostream功能的内部代码,看看他们是如何做到的.我考虑了几个选项:

  1. 对于异常的每个原因,我可以定义my_exception的静态实例,使用构造函数获取字符串并将其保存到我的私有字符串指针.

  2. 对于异常的每个原因,我可以定义另一个继承自my_exception的类,并实现作为返回常量字符串的函数(原因).我可以保存每个异常子类的实例,或抛出类型.顺便说一句,我们什么时候通常抛出类型而不是实例?

  3. 我想这是错的:每次我想抛出一个异常,用一个获取字符串的构造函数创建一个新的my_exception.这是用Java完成的,但据我所知,它在C++中会有问题,因为异常应该在某处删除.对?

我认为第一个是正确的,是吗?有更多标准选项吗?

非常感谢你!

jwi*_*mar 18

简短回答:您将要将异常作为对象抛出,而不是作为指针.你会把它们作为参考.

更长的答案:您列出的所有选项都有效.一般来说,你想要抛出一个对象而不是一个指针的原因是因为你捕获异常时给自己和你的客户提供的选择.

如果你通过指针捕获,catch (my_exception* e)那么你不知道是否应该删除内存.

如果按值捕获,catch (my_exception e)那么如果异常对象最终成为带有其他派生类的基类,则存在切片风险.

通过引用捕获没有这些问题.如果你写,catch (my_exception& r)那么你可以捕捉多态对象,你不必担心释放内存.

所以,回答你的另一个问题,当你抛出时,只需抛出一个临时物体:throw my_exception().这会创建一个临时对象(可能)在被抛出时被复制,被引用捕获,并在它超出catch块末尾的范围时自动销毁.(这实际上是引用引用的另一个好处,而不是按值跟踪,因为按值捕获会在捕获时创建另一个副本.)

至于你的其他派生异常类,它是一种风格选择.使用不同的what()实现从my_exception派生是非常标准的.我不会说您需要将字符串或实例存储在静态对象中 - 它们很小,并且构建一个实际上几乎没有时间与抛出异常时展开堆栈的过程相比.

  • 请注意,除非您打算修改异常(添加上下文并重新抛出),否则应通过const引用来捕获它。 (2认同)

Mar*_*ork 12

如果从std :: runtime_error派生,则不需要定义自己的成员来存储字符串.这是在std :: exception(std :: runtime_error的基础)中为您完成的.它没有定义异常如何存储字符串,但它应该始终有效.

#include <stdexcept>
#include <string>

struct MyException: public std::runtime_error
{
    MyException(std::string const& message)
        : std::runtime_error(message + " Was thrown")
    {}
};
Run Code Online (Sandbox Code Playgroud)

  • +1是个主意,但要讲究,`std :: exception`没有用于字符串或存储的构造函数,但是`std :: runtime_error`可以。(尽管如此,MSVC仍然在`std :: exception`中支持它。) (2认同)