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";
}
};
Здесь срез будет влиять на ваш результат.(Тем не менее, после всего этого: всегда ловить по ссылке.)