Domanda

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.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top