2

std::exception.what() とその派生クラスによって返される C 文字列の内容は実装定義ですが、clang、gcc、および Visual Studio は例外クラスの名前を示す C 文字列を返します。しかし、clang 3.2、gcc 4.7、および Visual Studio 2012 で次のコードを実行すると、奇妙な結果が得られます。

#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;
}

clang と gcc を使用すると、出力は次のようになります。

std::exception
std::bad_alloc

VS11 の出力は

bad allocation
bad allocation

私の理解では、clang と gcc は exception::what() を次のように実装しています。

const char* exception::what() const
{
    return __typename_demangle(typeid(*this).name());
}

すべての派生クラスが what() メソッドのこの実装を使用すること。上記のコードでe.what()typeid(e).name()に置き換えると、clang と gcc が出力されます

St9exception
St9bad_alloc

と VS11 出力

class std::exception
class std::bad_alloc

両方の catch ブロックで typeid が std::bad_alloc でない理由がわかりません。この動作により、what() メソッドが間違った値を返すようです。Microsoft は、std::exception から派生したすべてのクラスに対して what() の異なる簡単な実装を作成したに違いないため、VS11 はこの問題に悩まされません。

4

1 に答える 1

3

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.

于 2013-03-30T08:10:35.677 に答える