tags:

views:

405

answers:

4

Can a caught std::exception ever have what() being NULL?

Is the checking for e.what() below overhead?

//...
}
catch (const std::exception& e)
{
  std::string error;
  if(e.what())
    error = e.what();
}
+12  A: 

The contents of the string is implementation defined, so I guess the answer is yes.

Edit: Belay that. The standard says:

virtual const char* what() const throw();
5 Returns: An implementation-defined NTBS.

So it must return a string, not just a pointer. And a string cannot be NULL. As others have pointed out it is easy to derive exceptions whose what() does return NULL, but I'm not sure how such things fit into standards conformance. Certainly, if you are implementing what() in your own exception class, I would consider it very bad practice to allow it to return NULL.

More:

For a further question addressing whether what() can return NULL, and similar exciting issues, please see http://stackoverflow.com/questions/1073958/extending-the-c-standard-library-by-inheritance

anon
Net Citizen
It's virtual though so it's possible for bad programmers to make it NULL
JaredPar
Interesting. Now, since I know that some folk like to implement what via an std::string and the c_str() method therein, I have to ask - can c_str() of a properly constructed std::string ever return NULL? (I'm asking because I've got this situation in the codebase I work with and I want to know if I need to go add some TODOs or not).
Michael Kohne
c_str() for std:;string can never return NULL.
anon
@Net Citizen: The standard saying that it must not be NULL is a law as in "court", not a "physical law" -- it only says something should not be done, it can't prevent someone from breaking the law. (There's no reasonable way that C++ compiler/library implementors could actually provide a "physical law" that would prevent such code from compiling in C++.)
j_random_hacker
@j_random_hacker, they could in this case if the chose the return to be std::string vs. const char*. This would enforce at strong level at least a valid empty string. But much too late for that :(.
JaredPar
@JaredPar Returning a string involves memory allocation, which might be undesirable if you were trying to report a memory allocation failure.
anon
Intentionally not a std::string - it has to work for std::bad_alloc::what()
MSalters
@Net Citizen - I'd actually go with a code review of all exception classes in the system and make sure they don't return NULL. There probably aren't that many in a given system, and you can save a lot of excess code by doing a little work up front.
Michael Kohne
The key point is that to have proper inheritance, base class promises must be preserved. Therefore if the base class function promises never to return NULL (which appears to be the case here), any derived classes must promise the same, otherwise the inheritance is improper (broken).
markh44
+2  A: 

Of course it can be NULL:

class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return NULL;
  }
} myex;
schnaader
It is possible to do this **in the language** (i.e. your code will compile), but this is outlawed by the C++ standard -- see Neil's answer. IOW, don't do this, since other people's code might rely on you not doing this.
j_random_hacker
I don't think it is "outlawed" - the standard specifies the behaviour of std::exception::what - it doesn't seem to make any requirements of user classed deriving from std::exception.
Joe Gauterin
+4  A: 

If someone has inherited from std::exception and overridden what to return NULL, then this is possible.

   class CMyException : public std::exception
   {
   ...
       virtual const char * what () const {return NULL;}
   };

Despite Neil's excellent find in the standard, It might still be good to check for NULL. Although the specifications of what child classes of std::exception state they should not return a NULL, nothing in your compiler is going to enforce this and the above code will still be legal according to the language.

This may be an ideal situation to use an assert...

 assert(except.what() != NULL);

or

 if (except.what() != NULL)
 {
      ... normal processing ...
 }
 else
 {
      assert(false);
 }

because this is a case where something probably should never ever happen, and you are assuming it shouldn't happen, but would still like to know (in debug mode) when your assumptions are shown to be wrong. Then you can either address your incorrect assumption or address the incorrect code which may be going against your assumption (make sure what() doesn't return NULL).

Doug T.
It is possible **in the language** (i.e. your code will compile), but this is outlawed by the C++ standard -- see Neil's answer.
j_random_hacker
Yeah, i'm not sure whether it isn't undefined behavior if you just return NULL. It's violating what it specifies for what().
Johannes Schaub - litb
A: 

As many others have pointed out, what() shouldn't return a null pointer but it might. The runtime overhead of a null test is only incurred in the exceptional case where, presumably, it is less important.

In any case, I'd recommend at least using an assert.

If code space is also a concern, hopefully the assert, your testing, code reviews and other QA will be complete enough to track down any offending, non-compliant exceptions before you ship.

Also, be careful with exception handling code that can itself throw (for example, as others have noted, allocating memory with std::string while processing a std::bad_alloc exception.)

jwfearn
Allocating memory is not a good idea while processing std::bad_alloc. For other exceptions there is no sense to not to use std::string.
Kirill V. Lyadvinsky
good point, I edited my post to be a more general warning.
jwfearn