C ++, оправдано ли это утверждение goto? - PullRequest
9 голосов
/ 27 июля 2010

Я немного изменил заголовок, потому что я подумал, что это более подходящий вопрос.

Не могли бы вы изменить его (кажется, законное использование goto)?Если, как бы вы изменили рефакторинг следующего кода для удаления go to Statement?

if (data.device) {
    try {
        ...
    }
    catch(const std::exception&) { goto done; }
    ... // more things which should not be caught
done: ;
}

полный текст заявления

#ifdef HAVE_GPU
            // attempt to use GPU device
            if (data.device) {
                try {
                    Integral::Gpu eri(S, R, Q, block.shell());
                    eri(basis.centers(), quartets, data.device);
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) { goto done; }
                data.device += size;
                host_index.extend(block_index);
                block_index.data.clear();
            done: ;
            }
#endif

спасибо

После того, как я увидел предпочтение большинства, я решил пойти с флагом, но с комментарием мистера Йорка.1011 *

Спасибо всем

Ответы [ 14 ]

1 голос
/ 27 июля 2010

Причина, по которой goto осуждается сегодня, заключается в том, что вместо этого у нас есть такие причудливые вещи, называемые «функциями».Оберните код графического процессора в свою собственную функцию, которая может вернуться рано, если она не удалась.

Затем вызовите это из вашей исходной функции.

Так как им, вероятно, потребуется совместно использовать несколько переменных (data, host_index и block_index (похоже), поместите их в класс и сделайте из него две функции.

void RunOnGpu(){
        // attempt to use GPU device
        if (data.device) {
            try {
                Integral::Gpu eri(S, R, Q, block.shell());
                eri(basis.centers(), quartets, data.device);
            }
            // if GPU fails, propagate to cpu
            catch(std::exception) { return; }
            data.device += size;
            host_index.extend(block_index);
            block_index.data.clear();     
}
void DoStuff() {
#ifdef HAVE_GPU
    RunOnGpu();
#endif
}
1 голос
/ 27 июля 2010

Просто разбейте его на его собственную функцию / метод (включая все после него) и используйте ключевое слово return.Пока все ваши переменные имеют деструкторы, распределяются по стеку (или умно-указываются, если их невозможно избежать), все в порядке.Я большой поклонник функций / методов раннего выхода, а не постоянной проверки флагов.

например:

void myFunc()
{
    String mystr("heya");
    try
    {
        couldThrow(mystr);
    }
    catch(MyException& ex)
    {
        return; // String mystr is freed upon returning
    }

    // Only execute here if no exceptions above
    doStuff();
}

Таким образом, трудно ошибиться

1 голос
/ 27 июля 2010
catch(std::exception) { return; }

Это должно сработать. Я, конечно, предполагаю, что done действительно находится в конце функции.

Если вам нужно выполнить дополнительный код при возникновении исключения, верните статус или сгенерируйте исключение, которое находится на более правильном уровне абстракции (см. Ответ Джеймса).

Я представляю что-то вроде:

doStuff(...) {
    bool gpuSuccess = doGPUStuff(...);
    if (!gpuSuccess) {
        doCPUStuff(...);
    }
}
1 голос
/ 27 июля 2010

Как насчет использования какого-либо флага и добавления условного оператора?

int caught = 0;
if (data.device) {
    try {
        /* ... */
    } catch (std::exception e) { caught = 1; }
    if (!caught) {
        // more stuff here
    }
    // done: ...
}
...