2015-09-14 3 views
4

Я знаю, что люди всегда говорят, что не используют longjmp, это зло, это опасно.Безопасное использование `setjmp` и` longjmp`

Но я думаю, что это может быть полезно для выхода из глубоких рекурсий/вложенных вызовов функций.

Является ли один longjmp быстрее, чем много повторных проверок и возвратов, таких как if(returnVal != SUCCESS) return returnVal;?

Что касается безопасности, при условии, что динамическая память и другие ресурсы будут выпущены должным образом, проблем не должно быть, не так ли?

До сих пор, кажется, использование longjmp не составляет труда, и это даже делает мой код термином. Я испытываю желание использовать его много.

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

+3

Это может быть полезно в некоторых случаях, если вы знаете о возможных проблемах, которые могут возникнуть, и готовы рискнуть «кодом спагетти», который он может произвести. –

+0

«* кажется, использование longjmp не сложно, и даже делает мой код terser *» и более сложным, что более * сложно * поддерживать. – alk

+0

Возможно дубликат: http://stackoverflow.com/q/819864/694576 – alk

ответ

4

setjmp и longjmp можно рассматривать как механизм бедного человека exception. BTW, Ocaml исключения выполняются так же быстро, как setjmp, но имеют более четкую семантику.

Конечно, longjmp намного быстрее, чем повторное возвращение кодов ошибок в промежуточных функциях, так как оно всплывает, возможно, значительная часть call stack.

(я неявно сосредоточив внимание на Linux)

Они действительны и полезны, пока ресурсы не распределяются между ними, в том числе:

  • динамической памяти (malloc)
  • fopen -информация FILE* ручки
  • открытие дескрипторов файловой системы операционной системы (например, для сокетов)
  • другие ресурсы операционной системы, такие как таймеры или обработчики сигналов
  • получение некоторого внешнего ресурса, управляемого некоторым сервером, например. X11 окна (отсюда с помощью любого виджета инструментария как GTK), или дескриптор базы данных или соединение ...
  • и т.д ...

Основная проблема заключается в том, что , что свойство не leaking resources является глобальным общеправительственного программа свойство (или, по крайней мере, глобальные для всех функций, возможно, называемых между setjmp и longjmp), поэтому он запрещает modular software development: любой другой коллега, имеющим улучшить код в любой функции между setjmp и longjmp должен быть в курсе, что ограничения и следует, что дисциплина.

Следовательно, если вы используетеsetjmp документ, который очень четко.

Кстати, если вы только забота о malloc, используя систематическиBoehm's консервативны garbage collector поможет многое; вы будете использовать GC_malloc вместо malloc всюду, и вам все равно, free, и практически этого достаточно; то вы можете использовать setjmp без страхов (так как вы можете позвонить по телефону GC_malloc между setjmp и longjmp).

(обратите внимание, что понятия и терминология вокруг сборщика мусора вполне связаны с обработкой исключений и setjmp, но многие люди не знают их недостаточно. Чтение Garbage Collection Handbook должно быть полезным)

Читайте также о RAII и узнать об C++11 исключениях (и их отношение к destructors). Узнайте немного о continuations и CPS.

Read setjmp(3), longjmp(3) (а также о sigsetjmp, siglongjmp и setcontext(3)) и быть в курсе, что компилятор должен знать о setjmp

2

Следует отметить, что вызов setjmp в некоторых случаях не гарантированно безопасна (например, вы не можете переносить возвращаемое значение setjmp).

Кроме того, если вы хотите получить доступ к локальным переменным после вызова setjmp, в той же функции, которая могла быть изменена, вы должны пометить эти переменные как изменчивые.

Использование setjmp и longjmp также полезно, поскольку если рекурсия вызывает переполнение стека, вы можете восстановить с помощью longjmp из обработчика сигнала (не забудьте установить альтернативный стек) и вместо этого вернуть ошибку. Если вы хотите сделать это, вы должны рассмотреть возможность использования sigsetjmp и siglongjmp для сохранения диспозиций сигналов.

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