当RAII对象无法构造时

时间:2010-10-31 15:07:28

标签: c++ 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的默认构造函数不会抛出,这可能有所帮助,但这不是一般情况。一个构造函数可能会抛出。如果我想处理任何资源获取失败,如果没有投掷仍然能够继续,我该怎么做?

编辑:为了澄清,我的问题是如果资源无法获取,那么我可能想再试一次,依此类推。也许我可以尝试获得替代资源。

4 个答案:

答案 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;
}