当 RAII 对象构建失败时
假设我构造一个 RAII 对象,该对象可能无法构造。我该如何处理这个问题?
try {
std::vector<int> v(LOTS);
// try scope ends here because that's what the catch is for
} catch( const std::bad_alloc& ) {
// ...
}
// v? what v?
当然,std::vector 的默认构造函数不会抛出异常,这会有所帮助,但这不是一般情况。构造函数很可能会抛出异常。如果我想处理任何资源获取失败,我该如何做到这一点,同时在它不抛出时仍然能够继续?
编辑:澄清一下,我的问题是,如果资源无法获取,那么我可能想重试,依此类推。也许我可以尝试获取替代资源。
Suppose I construct a RAII object, and that object may fail to construct. How do I handle this?
try {
std::vector<int> v(LOTS);
// try scope ends here because that's what the catch is for
} catch( const std::bad_alloc& ) {
// ...
}
// v? what v?
Granted, the default constructor of std::vector
won't throw and that can help, but this is not the general case. A constructor may very well throw. If I want to handle any resource acquisition failure, how do I do that while still being able to proceed if it doesn't throw?
Edit: To clarify, my issue is that if a resource fails to acquire then I might want to try again, and so on. Maybe I can try acquiring an alternative resource.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
取决于你所说的“继续”是什么意思。无论什么操作需要资源都会失败:这就是“需要”的含义。因此,当您想在错误后继续时,您可能最终会编写如下代码:
这就是为什么您应该只在可以用它们做一些值得做的事情时捕获异常(在这种情况下,报告失败并继续进行下一个事情ummy) 。
如果您想在失败时重试,但前提是构造函数失败,而不是其他任何失败:
这或多或少是
std::new_handler
的工作方式 - 在 catch 中调用处理程序类似循环的子句,尽管不需要标志。如果您想在失败时尝试不同的资源:
如果“use v”和“use w”基本上是相同的代码,则重构为函数并从两个地方调用它。此时你的函数正在做很多事情。
Depends what you mean by "proceed". Whatever operation requires the resource will fail: that's what "requires" means. So when you want to continue after an error, you might end up writing code like this:
That's why you should only catch exceptions when there's something worthwhile you can do with them (in this case, report failure and move on to the next thingummy).
If you want to try again on failure, but only if the constructor fails, not if anything else fails:
This is more-or-less how
std::new_handler
works - the handler is called in the catch clause of a similar loop, although with no need for a flag.If you want to try a different resource on failure:
If "use v" and "use w" are basically the same code, then refactor into a function and call it from both places. Your function is doing quite a lot at this point.
如果 RAII 构造函数抛出异常,则抛出点之前绑定到 RAII 对象的所有资源都将被正确清理。 C++ 规则的设计合理就是为了保证这一点。
如果您的
v
构造由于bad_alloc
而抛出异常,则在try
块中的v
之前创建的任何 RAII 对象都将得到妥善清理。因此,如果您随后使用 RAII,则不需要像这样手动
try
/catch
,因为 RAII 对象会为您处理清理工作。如果您出于某种原因确实需要它,在上面的情况下您可以像下面这样使用交换。If an RAII constructor throws, all resources bound to RAII objects prior to the throwing point will be cleaned up properly. The C++ rules are sensibly designed to guarantee that.
If your
v
construction throws because of abad_alloc
then any RAII object created prior tov
in thetry
block will be properly cleaned up.So if you consequently use RAII, you don't need a manual
try
/catch
like that, because the RAII objects handle cleanup for you. If you do need it for some reason, in the case above you could use swap like the following.如果无法创建
v
,则所有尝试使用v
的代码都无法执行。将catch
移到 code 使用v
的代码后面,放在如果没有v
则可以合理继续执行的位置。If
v
can't be created, all the code that tries to usev
can't be executed. Move thecatch
after the code that code usesv
, in a place where it is reasonable to continue execution if there is nov
.所有使用 v 的代码都需要位于 try 块中。如果问题是如何缩小抛出异常的代码范围,您可以使用某种标志来指示您在 try 块中的位置,如下所示:
All code that uses v needs to be in the try block. If the question is how to then narrow down the code which threw the exception, you can use some kind of flag to indicate where in the try block you are, like this: