Когда не удается создать объект RAII - PullRequest
5 голосов
/ 31 октября 2010

Предположим, я создаю объект 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 ]

7 голосов
/ 31 октября 2010

Зависит от того, что вы подразумеваете под «продолжить». Независимо от того, какая операция требует, ресурс потерпит неудачу: вот что означает «требует». Поэтому, если вы хотите продолжить после ошибки, вы можете написать код:

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" - это в основном один и тот же код, то рефакторинг в функцию и вызов ее из обоих мест. Ваша функция делает довольно много в этот момент.

7 голосов
/ 31 октября 2010

Если сгенерирует конструктор RAII, все ресурсы, связанные с объектами RAII до точки выброса, будут очищены должным образом.Правила C ++ разумно разработаны, чтобы гарантировать, что.

Если ваша конструкция v выбрасывается из-за bad_alloc, то любой объект RAII, созданный до v в блоке try, будет должным образом очищен,

Таким образом, если вы, следовательно, используете 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!
2 голосов
/ 31 октября 2010

Если v не может быть создано, весь код, который пытается использовать v, не может быть выполнен.Переместите catch после кода, который использует код v, в место, где целесообразно продолжить выполнение, если v.

нет.
0 голосов
/ 31 октября 2010

Весь код, который использует 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;
}
...