C++, этот оператор перехода гарантирован?

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

Вы осуществили бы рефакторинг его (походит на законное использование goto)? Если, как Вы осуществили бы рефакторинг следующий код для удаления, переходят к оператору?

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

спасибо

после видели предпочтение большинства, я решил пойти с флагом, но с комментарием г-на York.

Поблагодарите Вас все

9
задан Anycorn 28 July 2010 в 03:19
поделиться

14 ответов

if (data.device)
{
    bool status = true;

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

    if (status)
    {
    ... // more things which should not be caught
    }
}
15
ответ дан 4 December 2019 в 05:58
поделиться

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

int caught = 0;
if (data.device) {
    try {
        /* ... */
    } catch (std::exception e) { caught = 1; }
    if (!caught) {
        // more stuff here
    }
    // done: ...
}
1
ответ дан 4 December 2019 в 05:58
поделиться

Просто разбейте ее на отдельную функцию / метод (включая все, что находится после нее) и используйте 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
ответ дан 4 December 2019 в 05:58
поделиться

Можно ли не перехватить исключение вне if?

2
ответ дан 4 December 2019 в 05:58
поделиться

Думаю, вам подойдет вариант.

// 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_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
ответ дан 4 December 2019 в 05:58
поделиться

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

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

#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
ответ дан 4 December 2019 в 05:58
поделиться

Почему бы не переместить дополнительный код внутрь блока 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
4
ответ дан 4 December 2019 в 05:58
поделиться

Во-первых: goto само по себе не является злом. Рефакторинг только ради того, чтобы в коде не было буквы "goto" - это нонсенс. Рефакторинг на что-то, что делает то же самое чище, чем goto, - это нормально. Изменение плохого дизайна на тот, который лучше и не нуждается в goto или его замене - тоже нормально.

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

8
ответ дан 4 December 2019 в 05:58
поделиться

Я что-то упустил, или это было бы эквивалентно перемещению части между меткой 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
ответ дан 4 December 2019 в 05:58
поделиться

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

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

Поскольку им, вероятно, придется совместно использовать несколько переменных (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
ответ дан 4 December 2019 в 05:58
поделиться
catch(std::exception) { return; }

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

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

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

doStuff(...) {
    bool gpuSuccess = doGPUStuff(...);
    if (!gpuSuccess) {
        doCPUStuff(...);
    }
}
1
ответ дан 4 December 2019 в 05:58
поделиться

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

// 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
}
7
ответ дан 4 December 2019 в 05:58
поделиться
if (data.device) {
    bool ok = true;
    try {
        ...
    }
    catch(std::exception) { ok = false; }

    if(ok) {
        ... // more things which should not be caught
    }
}
3
ответ дан 4 December 2019 в 05:58
поделиться

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

2
ответ дан 4 December 2019 в 05:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: