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 ]

15 голосов
/ 27 июля 2010
if (data.device)
{
    bool status = true;

    try
    {
        ...
    }
    catch(std::exception)
    {
        status = false;
    }

    if (status)
    {
    ... // more things which should not be caught
    }
}
8 голосов
/ 27 июля 2010

Первое: goto не является злом как таковым.Рефакторинг просто ради того, чтобы в вашем коде не было букв «goto», - чепуха.Рефакторинг этого к чему-то, что делает то же самое более чистым, чем goto, это хорошо.Замена плохого дизайна на лучший, не требующий перехода или замены, тоже подойдет.

При этом я бы сказал, что ваш код выглядит точно так же, как и был изобретен,Очень жаль, что в C ++ нет ничего подобного ... так что, возможно, самое простое решение - оставить это так.

7 голосов
/ 27 июля 2010

Вы можете перехватить исключение и повторно вызвать конкретное исключение, которое может быть обработано вне условного блока.

// obviously you would want to name this appropriately...
struct specific_exception : std::exception { };

try {
    if (data.device) {
        try {
            // ...
        }
        catch(const std::exception&) { 
            throw specific_exception(); 
        }

        // ... more things which should not be caught ...
    }
}
catch (const specific_exception&) { 
    // handle exception
}
4 голосов
/ 27 июля 2010

Немного другое использование флага. Я думаю, что это аккуратнее, чем у Амардипа.

Я бы предпочел использовать флаг, чтобы указать, следует ли распространять исключение, чем флаг, чтобы указать, сработала ли последняя вещь, потому что вся точка исключения исключает проверку того, является ли последняя вещь сработало - идея в том, чтобы написать код таким образом, чтобы, если мы зашли так далеко, то все сработало, и мы готовы продолжить.

#ifdef HAVE_GPU
    // attempt to use GPU device
    if (data.device) {
        bool dont_catch = false;
        try {
            ...
            dont_catch = true;
            ... // more things which should not be caught
        } catch (...) {
            if (dont_catch) throw;
        }
    }
#endif
4 голосов
/ 27 июля 2010

Я думаю, что вариант этого может работать для вас.

// attempt to use GPU device
if (data.device)
{
    try
    {
        Integral::Gpu eri(S, R, Q, block.shell());
        eri(basis.centers(), quartets, data.device);

        data.device += size;
        host_index.extend(block_index);
        block_index.data.clear();
    }
    catch (const std::bad_alloc&)
    {
        // this failure was not because 
        // of the GPU, let it propagate
        throw;
    }
    catch(...)
    {
        // handle any other exceptions by
        // knowing it was the GPU and we 
        // can fall back onto the CPU.
    }
}

// do CPU

Если вы могли бы отредактировать библиотеку GPU и дать всем исключениям GPU некоторую базу, например gpu_exception, код станет намного проще:

// attempt to use GPU device
if (data.device)
{
    try
    {
        Integral::Gpu eri(S, R, Q, block.shell());
        eri(basis.centers(), quartets, data.device);

        data.device += size;
        host_index.extend(block_index);
        block_index.data.clear();
    }
    catch (const gpu_exception&)
    {
        // handle GPU exceptions by
        // doing nothing and falling
        // back onto the CPU.
    }

    // all other exceptions, not being 
    // GPU caused, may propagate normally
}

// do CPU

Если ни одна из этих работ, я думаю, что следующая лучшая вещь - Ответ Стива .

4 голосов
/ 27 июля 2010

Почему бы не переместить дополнительный код в блок try?:

#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);
                    data.device += size;
                    host_index.extend(block_index);
                    block_index.data.clear();
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) { /* handle your exception */; }
            }
#endif
3 голосов
/ 27 июля 2010
if (data.device) {
    bool ok = true;
    try {
        ...
    }
    catch(std::exception) { ok = false; }

    if(ok) {
        ... // more things which should not be caught
    }
}
2 голосов
/ 27 июля 2010

Я что-то упустил или не будет эквивалентно перемещать деталь между меткой catch и done: внутри блока try?

#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);
                    data.device += size;
                    host_index.extend(block_index);
                    block_index.data.clear();
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) {}
            }
#endif
2 голосов
/ 27 июля 2010

Когда есть куча кода, который необходимо завершить на основании какого-либо условия, моя предпочтительная конструкция - использовать цикл «do {} while (0)» и «break», когда это необходимо. Я не знаю, что сломать; будет делать в улове, хотя. "Goto" может быть вашим лучшим выбором, если "break" не сработает.

2 голосов
/ 27 июля 2010

Разве вы не можете поймать исключение за пределами if?

...