I have a little function (in a DLL) which looks like this:
int my_function(const char* const s)
{
try {
return my_object->do_something_with(s);
} catch (exception& e) {
return ERROR_CODE;
}
}
I thought that the try-catch block would prevent anything which might happen inside my_object
from propagating to the outside. Unfortunately, I was wrong, and my program which calls this function (from VB) just stopped working because I had passed a null pointer argument.
So, why is my try-catch block not working as (I) expected? Is there a workaround? I used to program a lot in Java and I think it would have worked there ...
There is no NullPointerException in C++. If you really want to catch such an access, you must catch some signals (SIGSEGFAULT for example).
Dereferencing a null pointer in C++ is undefined behavior. This means the C++ standard doesn't put any limits on what may happen. Anything is permitted - a particular implementation might document its own behavior, or it might not. If it doesn't, the behavior might be consistent and predictable, or it might not.
In general it's best to assume that undefined behavior will cause your computer to catch fire (or format the hard disk). Just don't provoke it. Of course it's difficult to avoid errors in the first cut of your code, so when you do it by accident and your computer doesn't catch fire, then you were lucky, fix the bug and move on. Your function could be rewritten:
Alternatively you could fix the caller to not pass a null pointer in the first place, or you could fix
do_something_with
to accept a null pointer. C++ functions with pointer parameters should document whether or not null pointers are permitted.Different people will write the test
(s==0)
differently - it could be(s==NULL)
or(NULL==s)
or(!s)
. Pick one you like.In practice of course, compilers have good reasons not to set your computer on fire, and modern OSes try to ensure that badly-behaved apps don't massively inconvenience other apps. So on most systems, most of the time, when you dereference a null pointer you'll get some kind of hardware exception or signal, or your process will be killed, or perhaps on an embedded system the device will lock up and need a reboot.
You will not in general get a C++-style software exception that you can catch with any kind of catch clause, although Windows does have a feature called SEH which you can use to get that behavior.
Take it with a grain of salt because I haven't touched a C++ compiler since 1999. So much has changed with the STL and C++ that maybe things have changed. However, this is what I recall.
The exception model in C++ is very different from the one in Java. You have to be a lot, lot, but lot more proactive in checking for errors (and in throwing your own custom exceptions).
In Java, a call to de-reference a reference is ultimately a bytecode instruction sent and interpreted by the JVM. The JVM always check (internally) if the reference is null , and when it finds that it is, it automatically throws a java.lang.NullPointerException.
If the JVM weren't programmed to do such a thing, an access to a null reference would cause the JVM to crash with a SEGFAULT - exactly the behavior one would expect with a compiled, unguarded language when encountering an unguarded null pointer de-referencing (not just C or C++ but also in Pascal, Ada, Assembly or even good old BASIC attempting to do a PEEK/POKE at an invalid address location.)
The way (at least in my time) in C++ (or in any of the languages I've mentioned) was to explicitly check if the pointer (or the address being assigned to a reference) was null. At that point, if the test returns true, you launch your exception. You don't blindly go after the pointer. You gotta explicitly test it for null (or have a very strongly guaranteed pre-condition that the pointer actually points to the thing you need to get access to) before de-referencing.
This is somewhat equivalent to the following Java pseudocode
Things might be done differently now in C++, specially now with the C++0x stuff coming down the pipe (of which I have no clue about.) But at least, that's the behavior I had to deal with when coding in C++.
In other words, there is a lot more elbow grease involved in getting such things done. Remember that you are working at a lower level of abstraction from the one provided by the JVM.
The JVM is a barrier that gives you a lot of nice error-handling capabilities (one which we Java developers tend to rely too much on.) Those error-handling capabilities need to be explicitly be coded when you work at a lower level (not just in C++.)
In C++, anything can be thrown, and that anything does not necessarily derive from
std::exception
, which I'm assuming you're catching (using namespace std?).If you want to catch everything that can possibly be thrown, you can use a catch-all,
catch (...)
. This will catch any exception, but you won't know what the exception it caught is. It's always better to catch specific exceptions, where possible.Note that normally, a catch all will not handle lower level exceptions such as access violations. If you're using Windows and Visual Studio, you can configure your project to make catch-all blocks handle these exceptions with /EHa, but doing this is often dangerous and not suggested.
c++ faq items regarding exceptions might help you understand c++ exceptions better.
Lots of people programming in java have a problem understanding pointers and references, so if the program stopped working, maybe it was due to a crash (segmentation fault due to dereferencing NULL?)
It would have worked in Java, because in Java a
NullPointerException
is thown. In C++, there's no such ubiquitous exception, dereferencing a null pointer will just give a segmentation fault.Additionally, in C++ there is no enforced exception type hierarchy. An exception of any type may be thrown; exceptions don't have to derive from
std::exception
. (So even if someone had defined aclass NullPointerException {};
, but had not designated it to derive fromstd::exception
, you still wouldn't be catching it.)