2014-02-17 4 views
3

Недавно я попытался ответить, что я думал, будет simple question по спецификации исключения noexcept. В результате я обнаружил, что мое фундаментальное понимание noexcept было неправильным.гарантии noexcept и надежности

При чтении the current draft standard, чтобы исправить мое недоразумение, я обнаружил, что задаю несколько вопросов о noexcept, на которые не ответил here.

  1. Должно ли noexcept считаться гарантией безопасности, что функция при вызове будет не только не бросать, но и не испортить состояние?
  2. Предполагая, что (1.) неверно: правильно ли использовать noexcept в качестве переносного FailFast, чтобы прервать приложение без очистки, чтобы предотвратить повреждение сохраненного состояния?

Разъяснение к (2): Цель состоит в том, чтобы предотвратить только деструктор вызовов дальше вверх по стеку от noexcept не предотвратить раскручивание внутри него. Это основано на предположении, что это идеальная среда RAII, а деструкторы в стеке могут вывести глобальное состояние в постоянство, таким образом развращая его.

Пример того, как раскручивание не сформованную:

#include <iostream> 
#include <exception> 

namespace{ 
    struct foo{ 
     void change_state() noexcept 
     { 
      // change state and fail 
      throw std::exception(); 
     } 
     ~foo(){ 
      std::cout << "Destructor called, saved state corrupted!" <<std::endl; 
     } 
    }; 
} 


int main(){ 
    ::std::set_terminate([](){ 
     std::cout<< "Terminate called" <<std::endl; 
    }); 

    foo f; 
    f.change_state(); 
    return 0; 
} 

Working example of noexcept

+0

как я понимаю 'noexcept': даже если эта штука бросает, я не хочу об этом знать. Таким образом, это действительно не работает для «безопасности» или «правильности», оно работает, предотвращая исключение исключения из-за этого, поэтому ваша программа не заканчивается. – user2485710

+1

Если исключение достигает самого внешнего блока функции, помеченной как «noexcept», вызывается 'std :: terminate'. Он не подавляет исключения вообще. Он обеспечивает барьер, по которому не могут быть исключены исключения – Mgetz

+0

, о чем я писал ранее, о _runtime_, 'noexcept' работает во время компиляции, поэтому это подсказка для компилятора, компилятор оценивает ваши программы и, если есть вероятность, что что-то бросает , у вас есть возможность исправить это до _runtime_, потому что оператор 'noexcept' не будет работать в _compile time_. В некотором смысле он работает как «свойства типа», вы определяете свойство, которое должно быть оценено как «true», если компилятор не предупреждает вас, если тест проходит, вы знаете, что в _runtime_ у вас будут свои типы, определенные в вашем условия «признаков». То же самое для 'noexcept'. – user2485710

ответ

2
  1. Да. Функция не должна коррумпировать состояние, период, независимо от того, выбрасывает он или нет. Тот факт, что он мог иметь хотел, чтобы выбросить исключение, не имеет значения. [Конечно, нет никакой гарантии, что это не приведет к сбою программы. Однако такое поведение должно быть документировано. ;-)]
  2. Mu. Функция не должна мешать бросать, если она ожидает бросить через noexcept; он должен просто позвонить std::terminate (или std::abort).
+0

Я понимаю, что вы получаете от того, что такой сбой должен быть явным и не полагаться на поведение 'noexcept'. Я полагаю, что я задумываюсь о теоретическом, когда функция с надписью «noexcept» вызывает функцию, которая бросает. Вы обнаруживаете исключение, а затем вызываете 'std :: terminate'? – Mgetz

+1

Eh ... если полезно, чтобы внешняя функция поймала и обработала исключение, тогда, конечно, это должно сделать это. После этого он должен, вероятно, называть «terminate», чтобы продемонстрировать, что он не мешает поддерживать инварианты класса. Одна из вещей «бросить» означает «но не беспокойтесь, мы в порядке». С учетом сказанного, если «бросок» - это дюйм экрана, вдали от «noexcept», это не имеет большого значения. – Sneftel

1

noexcept договорной гарантии, так же, как assert , который не может быть выключен. Если функция с пометкой noexcept пытается выйти из-за исключения, то пост-условие было нарушено , и вы не можете рассчитывать на что-либо; программа будет завершена. Таким образом, 1 ложно.

Что касается 2, это сложнее. Реализация может развернуть стеки до тех пор, пока она не попытается оставить функцию с noexcept; это не на 100% ясно (по крайней мере для меня), что он может не разматывать стек дальше. Если я хочу закончить приложение без очистки, я позвоню abort(), то есть гарантированно выйдет немедленно без каких-либо дальнейших действий. Он также сообщает читателю, что именно происходит, а не , рассчитывая на некоторый вторичный эффект другой функции.

+0

, чтобы вы могли обернуть какие-либо небезопасные (не-неэксклюзивные) вызовы в этом конкретном случае с помощью 'catch'? а затем вызвать 'std :: abort', чтобы предотвратить дальнейшее разматывание? (Я предполагаю, что разматывание в функции 'noexcept' не повредит сохраненное состояние) – Mgetz

+0

@Mgetz Обычно я не делал бы никаких небезопасных вызовов :-). В противном случае, я бы только обернул их, если бы захотел проглотить их (например, случай деструктора, который можно было бы вызвать во время разматывания стека). –

+0

Казалось бы, мой вопрос не ясен ... намерение состоит только в том, чтобы предотвратить вызовы деструктора дальше в стек, чем «noexcept». Но если я понимаю вас ... то, что вы говорите, заключается в том, что в таких случаях, когда глобальное сохраненное состояние может быть повреждено, лучше действовать, как если бы в контексте «noexcept», а затем просто «прерывать», если это необходимо немедленно. – Mgetz

Смежные вопросы