You can start by eliminating sources of NULL:
Change
if (error) {
return NULL;
}
Into
if (error) {
return DefaultObject; // Ex: an empty vector
}
If returning default objects does not apply and your code base already uses exceptions, do
if (error) {
throw BadThingHappenedException;
}
Then, add handling at appropriate places.
If you are working with legacy code, you could make some wrapper functions/classes:
ResultType *new_function() {
ResultType *result = legacy_function();
if (result) {
return result;
} else {
throw BadThingHappenedException;
}
}
New functionalities should start using new functions and have proper exception handling.
I know some programmers just don't get exceptions, including smart people like Joel. But, what ends up happening by returning NULL is that this NULL gets pass around like crazy since everybody would just think it's not their business to handle it and return silently. Some functions may return error code, which is fine, but the caller often ends up returning yet-another-NULL in response to errors. Then, you see a lot of NULL-checking in every single functions, no matter how trivial the function is. And, all it takes is just ONE place that doesn't check for NULL to crash the program. Exceptions force you to carefully think about the error and decide exactly where and how it should be handled.
It seems like you're just looking for easy solutions like static analysis tools (which you should always use). Changing pointers to references is also a great solution too. However, C++ has the beauty of RAII, which eliminates the need for having "try {} finally {}" everywhere, so I think it worths your serious consideration.