The contents of the C string returned by std::exception.what() and its derived classes is implementation defined, but clang, gcc, and Visual Studio return C strings that indicate the name of the exception class. But when I run the following code on clang 3.2, gcc 4.7, and Visual Studio 2012 I get strange results:
#include <iostream>
#include <exception>
int main(int argc, const char * argv[])
{
try {
throw std::bad_alloc();
} catch (std::exception e) {
std::cout << e.what() << std::endl;
}
try {
throw std::bad_alloc();
} catch (std::bad_alloc e) {
std::cout << e.what() << std::endl;
}
return 0;
}
With clang and gcc the output is
std::exception
std::bad_alloc
With VS11 the output is
bad allocation
bad allocation
My understanding is that clang and gcc implement exception::what() something like so
const char* exception::what() const
{
return __typename_demangle(typeid(*this).name());
}
and that all derived classes use this implementation of the what() method. If I replace e.what() with typeid(e).name() in the above code then clang and gcc output
St9exception
St9bad_alloc
and VS11 outputs
class std::exception
class std::bad_alloc
I don't understand why the typeid isn't std::bad_alloc for both catch blocks. This behavior appears to cause the what() method to return the wrong value. Microsoft must have created different, trivial implementations of what() for all of the classes derived from std::exception, so VS11 does not suffer from this issue.
You get this output because in the first case you create a new std::exception
object, and in the second - new std::bad_alloc
object. Instead of this you should catch exceptions by reference. The following code should show the difference:
#include <iostream>
#include <string>
class Foo
{
public:
Foo()
{
// std::cout << "Foo()" << std::endl;
}
Foo(const Foo&)
{
std::cout << "Foo(const Foo&)" << std::endl;
}
virtual ~Foo()
{
}
virtual std::string what() const
{
return "what: Foo";
}
};
class Bar: public Foo
{
public:
Bar()
{
// std::cout << "Bar()" << std::endl;
}
Bar(const Bar&)
{
std::cout << "Bar(const Bar&)" << std::endl;
}
std::string what() const
{
return "what: Bar";
}
};
int main()
{
try
{
throw Bar();
}
catch(Foo f)
{
std::cout << f.what() << std::endl;
}
try
{
throw Bar();
}
catch(const Foo& f)
{
std::cout << f.what() << std::endl;
}
return 0;
}
The output is
Foo(const Foo&)
what: Foo
what: Bar
But I don't have VS11, so I can't tell you, why is VS produces such an output. It will be nice if someone would clarify this.
Thanks to @BoPersson:
The different message in the OP's case is because VC++ implements what() by storing the message text in the exception base class. Other implementations do not.