Reputation: 5944
I know people always say don't use longjmp
, it's evil, it's dangerous.
But I think it can be useful for exiting deep recursions/nested function calls.
Is a single longjmp
faster than a lot of repeated checks and returns like if(returnVal != SUCCESS) return returnVal;
?
As for safety, as long as dynamic memory and other resources are released properly, there shouldn't be a problem, right?
So far it seems using longjmp
isn't difficult and it even makes my code terser. I'm tempted to use it a lot.
(IMHO in many cases there is no dynamic memory/resources allocated within a deep recursion in the first place. Deep function call seems more common for data parsing/manipulation/validation. Dynamic allocation often happens at a higher level, before invoking the function where setjmp
appears.)
Upvotes: 6
Views: 2836
Reputation: 1
setjmp
and longjmp
can be seen as a poor man's exception mechanism. BTW, Ocaml exceptions are as quick as setjmp
but have a much clearer semantics.
Of course a longjmp
is much faster than repeatedly returning error codes in intermediate functions, since it pops up a perhaps significant call stack portion.
(I am implicitly focusing on Linux)
They are valid and useful as long as no resources are allocated between them, including:
malloc
)fopen
-ing FILE*
handlesThe main issue is that that property of not leaking resources is a global whole-program property (or at least global to all functions possibly called between setjmp
and longjmp
), so it prohibits modular software development : any other colleague having to improve some code in any function between setjmp
and longjmp
has to be aware of that limitation and follow that discipline.
Hence, if you use setjmp
document that very clearly.
BTW, if you only care about malloc
, using systematically Boehm's conservative garbage collector would help a lot; you'll use GC_malloc
instead of malloc
everywhere and you won't care about free
, and practically that is enough; then you can use setjmp
without fears (since you could call GC_malloc
between setjmp
and longjmp
).
(notice that the concepts and the terminology around garbage collector are quite related to exception handling and setjmp
, but many people don't know them enough. Reading the Garbage Collection Handbook should be worthwhile)
Read also about RAII and learn about C++11 exceptions (and their relation to destructors). Learn a bit about continuations and CPS.
Read setjmp(3), longjmp(3) (and also about sigsetjmp
, siglongjmp
, and setcontext(3)) and be aware that the compiler has to know about setjmp
Upvotes: 8
Reputation: 1493
You should note that calling setjmp in some contexts is not guaranteed to be safe (for example, you can't portably store the return value of setjmp).
Also, if you want to access local variables after calling setjmp, in the same function, that could have been changed you should mark that variables as volatile.
Using setjmp and longjmp is also useful because if the recursion causes a Stack Overflow, you can recover with a longjmp from the signal handler (don't forget to set an alternate stack) and return an error instead. If you want to do that you should consider to use sigsetjmp and siglongjmp for preserving signal dispositions.
Upvotes: 3