我想构建一个具有函数的类,这些函数可能会在我使用它时抛出我想要捕获的异常。 我从标准异常类继承my_exception。 我实现了what()函数,以便它返回一个存储在私有字符串变量
中的字符串我认为将异常定义为嵌套类会更好,就像在iosream库中使用ios_base :: failure一样。
我不太确定,我应该在哪里以及如何定义my_excpetion的对象。我希望我能看到iostream功能的内部代码,看看他们是如何做到的。 我考虑了几个选项:
对于异常的每个原因,我可以定义my_exception的静态实例,使用一个构造函数获取字符串并将其保存到我的私有字符串指针。
对于异常的每个原因,我可以定义另一个继承自my_exception的类,并实现作为返回常量字符串的函数(原因)。 我可以保存每个异常子类的实例,或抛出类型。 顺便说一下,我们什么时候通常抛出类型而不是实例?
我想这是错的:每次我想抛出一个异常,用一个获取字符串的构造函数创建一个新的my_exception。这是用Java完成的,但据我所知,它在C ++中会有问题,因为异常应该在某处删除。右
我认为第一个是正确的,是吗? 有更多标准选项吗?
非常感谢!
答案 0 :(得分:18)
简短回答:您将要将异常作为对象抛出,而不是作为指针抛出。你会把它们作为参考。
更长的答案:您列出的所有选项都有效。一般来说,你想要抛出一个对象而不是一个指针的原因是因为你在抓住异常时给自己和你的客户做出的选择。
如果你用指针抓住catch (my_exception* e)
,那么你不知道是否应该删除内存。
如果按值catch (my_exception e)
捕获,那么如果异常对象最终成为带有其他派生类的基类,则存在切片风险。
通过引用捕获没有这些问题。如果您编写catch (my_exception& r)
,那么您可以捕获多态对象,并且您不必担心释放内存。
所以,为了回答你的另一个问题,当你抛出时,只需抛出一个临时对象:throw my_exception()
。这会创建一个临时对象(可能)在被抛出时被复制,被引用捕获,并在它超出catch块末尾的范围时自动销毁。 (这实际上是追加引用的另一个好处,而不是按价值追踪,因为当它被捕获时,按价值追加创造了另一个副本。)
至于你的其他派生异常类,它是一种风格选择。使用不同的what()实现从my_exception派生是非常标准的。我不会说你需要将这些字符串或实例存储在静态对象中变得很奇怪 - 它们很小,与异常时解除堆栈的过程相比,构建一个实际上几乎没有时间被扔了。
答案 1 :(得分: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")
{}
};
答案 2 :(得分:0)
您的任何选项都没有错。数字3是可以的,只要你创建一个局部变量而不使用new
,因为没有必要删除异常对象 - 它会在你抛出后立即销毁。您需要创建一个复制构造函数和复制操作符,因为抛出的异常实际上是您为throw
语句提供的异常的副本。
选项1不常见,因为通常不需要。
对于选项2,您将创建要抛出的类的实例。不可能抛出一个类型,只能抛出一个类型的实例。