Routines like longjmp and exit should not be used in C++ programs.
C++ object semantics guarantee that local objects are destroyed when leaving their scope, regardless of whether the scope is exited by executing off the end of a block, returning from a subroutine, or throwing an exception. Unfortunately, some C library routines like longjmp can unwind multiple layers of the stack all at once. These routines do not respect C++ object semantics. That is, they do not tear down the intermediate stack frames one by one, destroying local objects as they go. This violates the C++ guarantee that destructors are always called when objects are torn down. Therefore routines like this should not be used in C++ programs.
One might argue that inspection of all existing calls demonstrates that a specific call to exit or longjmp is safe because all possible ancestors possess instances of local objects that need to be torn down. Nevertheless, this usage is unsafe and should be removed. In the future, new calls could be added that create the unsafe condition without warning. Therefore, this usage pattern is error-prone, even if it has not yet created an actual defect.
All such uses can be recoded in terms of C++ exceptions. That is, instead of calling "exit," one can throw an exception that is handled in the main routine. You can establish a catch clause, in place of calling setjmp and throwing an exception, which is caught in that clause in place of calling longjmp.
ID |
Observation |
Description |
---|---|---|
1 |
Call site |
The place where the operator was invoked |
#include <string.h> #include <stdlib.h> #include <iostream> using namespace std; // Class accumulates a string that gets // printed when the instance is destroyed class StringHolder { private: char *stringToPrint; public: explicit StringHolder(char * string) { size_t size = strlen(string) + 1; stringToPrint = (char *)malloc(size); strcpy_s(stringToPrint, size, string); } ~StringHolder() { cout << stringToPrint; free(stringToPrint); } // copy constructor StringHolder::StringHolder(const StringHolder & source) { size_t size = strlen(source.stringToPrint) + 1; stringToPrint = (char *)malloc(size); strcpy_s(stringToPrint, size, source.stringToPrint); } // assignment operator StringHolder& StringHolder::operator=(const StringHolder & source) { free(stringToPrint); size_t size = strlen(source.stringToPrint) + 1; stringToPrint = (char *)malloc(size); strcpy_s(stringToPrint, size, source.stringToPrint); return *this; } }; void f(int n) { if (n != 0) { StringHolder IDontGetDestroyed("Arguments present"); exit(0); } // Object IDontGetDestroyed never gets torn down // because of call to exit, so nothing gets printed } int main(int argc, char **argv) { f(argc); return 0; }
Copyright © 2010, Intel Corporation. All rights reserved.