当RAII对象无法构造时

wil*_*ell 5 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?
Run Code Online (Sandbox Code Playgroud)

当然,默认构造函数std::vector不会抛出,这可能有所帮助,但这不是一般情况.一个构造函数可能会抛出.如果我想处理任何资源获取失败,如果它没有抛出,我怎么能这样做仍然能够继续?

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

Joh*_*itb 7

如果RAII构造函数抛出,则在抛出点之前绑定到RAII对象的所有资源都将被正确清理.C++规则的合理设计是为了保证这一点.

如果你的v构造因为一个抛出bad_alloc那么vtry块之前创建的任何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!
Run Code Online (Sandbox Code Playgroud)


Ste*_*sop 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";
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么你应该只捕获例外情况,因为你可以用它们做一些有价值的事情(在这种情况下,报告失败并继续下一个事情).

如果要在失败时再次尝试,但仅当构造函数失败时,如果还有其他任何失败:

while(not bored of trying) {
    bool constructor_failed = true;
    try {
        vector<int> v(LOTS);
        constructor_failed = false;
        // use v
    } catch(...) {
        if (!constructor_failed) throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

这或多或少是std::new_handler有效的 - 在类似循环的catch子句中调用处理程序,尽管不需要标志.

如果您想在失败时尝试不同的资源:

try {
    vector<int> v(LOTS);
    // use v
} catch(...) try {
    otherthing<int> w(LOTS);
    // use w
} catch(...) {
    // failed
}
Run Code Online (Sandbox Code Playgroud)

如果"use v"和"use w"基本上是相同的代码,那么重构成一个函数并从两个地方调用它.你的功能在这一点上做了很多.

  • 对于最后一句,单独使用"+ 1".没有足够的程序员注意这一点.非常不幸. (2认同)