假设我构造了一个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
的默认构造函数不会抛出,这可能有所帮助,但这不是一般情况。一个构造函数可能会抛出。如果我想处理任何资源获取失败,如果没有投掷仍然能够继续,我该怎么做?
编辑:为了澄清,我的问题是如果资源无法获取,那么我可能想再试一次,依此类推。也许我可以尝试获得替代资源。
答案 0 :(得分:7)
如果RAII构造函数抛出,则在抛出点之前绑定到RAII对象的所有资源都将被正确清理。 C ++规则设计合理,以保证。
如果您的v
构造因bad_alloc
而失败,那么v
块中try
之前创建的任何RAII对象都将被正确清理。
因此,如果您因此使用RAII,则不需要手动try
/ catch
,因为RAII对象会为您处理清理。如果你做由于某种原因需要它,在上面的情况下你可以像下面这样使用swap。
std::vector<int> v;
try {
std::vector<int> vtry(LOTS);
v.swap(vtry); // no-throw
} catch( const std::bad_alloc& ) {
// ...
}
// v!
答案 1 :(得分:7)
取决于“继续”的意思。无论什么操作需要资源都会失败:这就是“需要”的意思。所以当你想在错误之后继续时,你最终可能会编写这样的代码:
void something_using_RAII(thingummy &t) {
vector<int> v(t.size_required);
// do something using v
}
...
for each thingummy {
try {
something_using_RAII(this_thingummy);
} catch(const std::bad_alloc &) {
std::cerr << "can't manage that one, sorry\n";
}
}
这就是为什么你应该只捕获异常,因为你可以用它们做一些有价值的东西(在这种情况下,报告失败并转到下一个东西)。
如果你想在失败时再试一次,但只有在构造函数失败的情况下才会再次尝试,而不是其他任何失败:
while(not bored of trying) {
bool constructor_failed = true;
try {
vector<int> v(LOTS);
constructor_failed = false;
// use v
} catch(...) {
if (!constructor_failed) throw;
}
}
这或多或少std::new_handler
如何工作 - 在类似循环的catch子句中调用处理程序,尽管不需要标记。
如果您想在失败时尝试不同的资源:
try {
vector<int> v(LOTS);
// use v
} catch(...) try {
otherthing<int> w(LOTS);
// use w
} catch(...) {
// failed
}
如果“使用v”和“使用w”基本上是相同的代码,则重构为函数并从两个地方调用它。你的功能在这一点上做了很多。
答案 2 :(得分:2)
如果无法创建v
,则无法执行尝试使用v
的所有代码。在代码使用catch
的代码之后移动v
,如果没有v
,则在合理的位置继续执行。
答案 3 :(得分:0)
使用v的所有代码都需要在try块中。如果问题是如何缩小抛出异常的代码,你可以使用某种标志来指示你在try块中的位置,如下所示:
string flag;
try
{
flag = "creating vector<int> v";
std::vector<int> v(LOTS);
flag = "performing blaggity bloop";
blaggity_bloop();
flag = "doing some other stuff";
some_other_stuff();
}
catch( const std::bad_alloc& )
{
cerr << "Bad allocation while " << flag << endl;
}