C++ 中的标准方式;定义异常类并抛出异常
我想构建一个类,其中的函数可能会引发我想在使用它时捕获的异常。 我从标准异常类继承 my_exception 。 我实现了 What() 函数,以便它返回一个存储在私有字符串变量中的字符串,
我认为最好将异常定义为嵌套类,就像在 iostream 库中使用 ios_base::failure 完成的那样。
我不太确定的是,我应该在哪里以及如何定义 my_excpetion 的对象。我希望我能看到 iostream 函数的内部代码并了解它们是如何做到的。 我考虑了几个选项:
对于每个异常原因,我可以定义一个 my_exception 的静态实例,并使用一个构造函数来获取字符串并将其保存到我的私有字符串指针。
对于每个异常原因,我可以定义另一个从 my_exception 继承的类,并将其实现为返回常量字符串(原因)的函数。 我可以保存每个异常子类的实例,或者抛出该类型。 顺便说一句,我们通常什么时候抛出类型而不是实例?
我猜这是错误的:每次我想抛出异常时,都要使用获取字符串的构造函数创建一个新的 my_exception 。这是在 Java 中完成的,但据我了解,这在 C++ 中会出现问题,因为应该在某个地方删除异常。对吗?
我认为第一个是正确的,是吗? 还有更多标准选项吗?
非常感谢!
I want to build a class with functions that may throw exceptions that I want to catch when I use it.
I inherit my_exception from the standard exception class.
I implement the what() function so that it returns a string that is stored in a private string variable
I think it would be better to define the exception as a nested class, the way it's done in iostream library with ios_base::failure.
What I'm less sure about, is where and how I should define the object of my_excpetion. I wish I could see the inner code of the iostream functions and see how they did it.
I have thought about several options:
For each reason of exception I can define a static instance of my_exception, with a constructor that gets a string and save it to my private string pointer.
For each reason of exception I can define another class that inherit from my_exception and implement what as a function that returns a constant string (the reason).
I can hold an instance of each of that exceptions sub-classes, or to throw the type.
BTW, when do we usually throw type and not instance?I guess it's wrong: each time I want to throw an exception, to create a new my_exception with a constructor that gets a string. This is done in Java, but as I understand it will be problematic in C++ because the exception should be deleted somewhere. Right?
I think that the 1st one is the right one, is it?
Are there more standard options?
Thank you very much!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
简短的回答:您将希望将异常作为对象而不是指针抛出。你会抓住它们作为参考。
更长的答案:您列出的所有选项都有效。一般来说,您想要抛出一个对象而不是指针的原因是因为捕获异常时您给自己和客户的选择。
如果你通过指针捕获,
catch (my_exception* e)
那么你不知道是否应该删除内存。如果您按值捕获,
catch (my_exception e)
,那么如果异常对象最终成为具有某些其他派生类的基类,那么您就有切片的风险。通过引用捕获不存在这些问题。如果你编写
catch(my_exception& r)
那么你就可以捕获多态对象,并且不必担心释放内存。因此,要回答您的另一个问题,当您抛出时,只需抛出一个临时对象:
throw my_exception()
。这会创建一个临时对象,该对象(可能)在抛出时被复制,通过引用捕获,并在 catch 块末尾超出范围时自动销毁。 (这实际上是按引用捕获相对于按值捕获的另一个好处,因为按值捕获在捕获时会创建另一个副本。)至于其他派生的异常类,这是一种样式选择。使用不同的 What() 实现从 my_Exception 派生是相当标准的。我不会说您需要花哨地将字符串或实例存储在静态对象中 - 它们很小,并且与抛出异常时展开堆栈的过程相比,构造一个几乎不需要时间。
Short answer: You are going to want to throw the exceptions as objects, rather than as pointers. You will catch them as references.
Longer answer: all of the options you list are valid. In general, the reason you are going to want to throw an object, rather than a pointer, is becuase of the choices you give yourself and your clients when the exception is caught.
If you catch by pointer,
catch (my_exception* e)
then you don't know from looking at it whether you should delete the memory or not.If you catch by value,
catch (my_exception e)
then you have a risk of slicing, if the exception object ends up being a base class with some other derived classes.Catching by reference has neither of these problems. If you write
catch (my_exception& r)
then you can catch polymorphic objects, and you don't have to worry about releasing the memory.So, to answer your other question, when you throw, just throw a temporary object:
throw my_exception()
. This creates a temporary object that is (probably) copied when thrown, caught by reference, and destroyed automatically when it goes out of scope at the end of your catch block. (This is actually another benefit of catch-by-reference over catch-by-value, since catch-by-value creates yet another copy when it's caught.)As for your other, derived exception classes, it's a style choice. Deriving from my_exception with a different what() implementation is pretty standard. I wouldn't say you need to get fancy with storing the strings or instances in static objects - they're small, and constructing one is going to take practically no time compared to the process of unwinding the stack when the exception is thrown.
如果您从 std::runtime_error 派生,则无需定义自己的成员来存储字符串。这是在 std::exception (std::runtime_error 的基础)中为您完成的。没有定义异常如何存储字符串,但它应该始终有效。
If you derive from std::runtime_error you do not need to define your own member to store the string. This is done for you in the std::exception (the base of std::runtime_error). It is not defined how the exception stores the string but it it should always work.
您的任何选择都没有问题。第三点是可以的,只要你创建一个局部变量并且不使用
new
,因为不需要删除异常对象 - 一旦抛出它就会被销毁。您将需要创建一个复制构造函数和复制运算符,因为抛出的异常实际上是您为throw
语句提供的异常的副本。选项 1 并不常见,因为通常没有必要。
对于选项 2,您将创建要抛出的类的实例。不可能抛出类型,只能抛出类型的实例。
Nothing wrong with any of your options. Number 3 is OK, as long as you make a local variable and not use
new
, because there's no need to delete the exception object - it will be destroyed as soon as you throw. You will need to make a copy constructor and copy operator, because the thrown exception will actually be a copy of the one you give to thethrow
statement.Option 1 would be unusual because it's not normally necessary.
For option 2 you would create an instance of the class to throw. It's not possible to throw a type, only an instance of a type.