12

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

我认为将异常定义为嵌套类会更好,就像在 iostream 库中使用 ios_base::failure 完成的方式一样。

我不太确定的是,我应该在哪里以及如何定义 my_excpetion 的对象。我希望我能看到 iostream 函数的内部代码,看看它们是如何做到的。我想过几个选择:

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

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

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

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

非常感谢你!

4

3 回答 3

18

简短的回答:您将希望将异常作为对象而不是指针来抛出。您将捕获它们作为参考。

更长的答案:您列出的所有选项都是有效的。通常,您要抛出对象而不是指针的原因是因为当捕获到异常时您给自己和客户的选择。

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

如果您按值捕获,catch (my_exception e)那么如果异常对象最终成为具有其他一些派生类的基类,那么您就有被切片的风险。

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

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

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

于 2011-05-28T04:53:28.280 回答
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")
    {}
};
于 2011-05-28T06:20:35.860 回答
0

您的任何选择都没有错。数字 3 是可以的,只要你创建一个局部变量而不是 use new,因为不需要删除异常对象 - 一旦你抛出它就会被销毁。您将需要创建一个复制构造函数和复制运算符,因为抛出的异常实际上是您提供给throw语句的异常的副本。

选项 1 将是不寻常的,因为它通常不是必需的。

对于选项 2,您将创建一个要抛出的类的实例。不可能抛出一个类型,只能抛出一个类型的实例。

于 2011-05-28T04:52:13.073 回答