Как получается, что `e.what ()` выводит "плохое распределение"? - PullRequest
5 голосов
/ 01 декабря 2011

Выражение new в блоке try вызывает исключение bad_alloc на моем компьютере.

Обратите внимание, что предложение catch получает объект исключения по значению, а не по ссылке. Почему e.what() печатает "bad allocation"? Я думал, что это будет нарезано.

#include <iostream>

int main()
{
    try
    {
        int* p = new int[0x1F000000];
    }
    catch(std::exception e)
    {
        std::cout << e.what() << std::endl;
    }
}

1 Ответ

13 голосов
/ 01 декабря 2011

Visual Studio (Dinkumware?) Использует реализацию std::exception, которая содержит внутреннее хранилище † для сообщения.(В комплекте с нестандартным конструктором, который принимает строку.)

Из-за этого фактически не требуется виртуальная диспетчеризация для получения сообщения об ошибке, он выживает при любом разрезании.Реализация действительно напечатает сообщение об исключительной ситуации, потому что производный объект был обрезан.(По сути, MS сделала std::exception и std::runtime_error эквивалентными. В этом нет ничего плохого, поскольку возвращаемое значение std::exception::what определяется реализацией, но объясняет ваши результаты.)


† Внутреннее хранилище здесь используется свободно.Он не имеет внутреннего буфера , но имеет const char* и bool.const char* указывает на сообщение (возвращаемое значение what()), а bool - это флаг, определяющий, следует ли удалять буфер.

Это выглядит так:

class msvc_exception // for exposition
{
public:
    msvc_exception(const char* msg) :
    mMsg(msg),
    mDoDelete(false)
    {}

    msvc_exception(const std::string& msg) :
    mMsg(copy_string(msg)),
    mDoDelete(true)
    {}

    virtual ~msvc_exception()
    {
        if (mDoDelete)
            delete [] mMsg;
    }

    virtual const char* what() const throw()
    {
        return mMsg ? mMsg : "unknown";
    }

private:
    const char* copy_string(const std::string& str)
    {
        const char* result = new char[str.size() + 1];

        std::copy(str.begin(), str.end(), result);
        result[str.size()] = 0; // null-terminate

        return result;
    }
};

Теперь вы видите, что bad_alloc работает следующим образом:

    class msvc_bad_alloc : // for exposition
        public msvc_exception
    {
    public:
        msvc_bad_alloc() :
        msvc_exception("bad_alloc") // note: a static string, no dynamic storage
        {}
    };

Нарезка не влияет на сообщение, поскольку сообщение «существует» в базовом классе.

Другие компиляторы,как GCC и LLVM, реализуйте это немного более просто:

class orthodox_exception
{
public:
    orthodox_exception(){}
    virtual ~orthodox_exception() {}

    virtual const char* what() const throw()
    {
        return "orthodox_exception";
    }
};

class orthodox_bad_alloc :
    public orthodox_exception
{
public:
    const char* what() const throw()
    {
        return "orthodox_bad_alloc";
    }
};

Здесь срез будет влиять на ваш результат.(Тем не менее, после всего этого: всегда ловить по ссылке.)

...