5

假设我构造了一个 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

4 回答 4

7

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

如果您的v构造由于 a 而引发,则在块中bad_alloc之前创建的任何 RAII 对象都将被正确清理。vtry

因此,如果您因此使用 RAII,则不需要像那样的手册trycatch因为 RAII 对象会为您处理清理工作。如果出于某种原因确实需要它,在上述情况下,您可以使用如下所示的交换。

std::vector<int> v;
try {
    std::vector<int> vtry(LOTS);
    v.swap(vtry); // no-throw
} catch( const std::bad_alloc& ) {
    // ...
}
// v!
于 2010-10-31T15:12:39.530 回答
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
}

如果“use v”和“use w”基本上是相同的代码,那么重构为一个函数并从两个地方调用它。在这一点上,您的功能正在做很多事情。

于 2010-10-31T15:13:05.757 回答
2

如果v无法创建,则所有尝试使用的代码v都无法执行。将catch代码使用的代码v移到没有 的情况下可以继续执行的地方v

于 2010-10-31T15:14:09.600 回答
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;
}
于 2010-10-31T16:13:24.477 回答