Это подразумевается как дополнение к ответу Бен Фойгта ', а не замене.
Вы можете подумать, что это всего лишь техническая часть.То, что стандарт, называющий его «неопределенный», - это всего лишь небольшая семантическая парадигма, которая не имеет реальных эффектов, за исключением того, что авторы компиляторов могут делать глупые вещи без веской причины.Но это не тот случай.
Я мог видеть желательные реализации, в которых:
Base *b = new Derived;
delete b;
Результатом было довольно странное поведение.Это связано с тем, что хранить размер выделенного фрагмента памяти, когда он статически известен компилятору, довольно глупо.Например:
struct Base {
};
struct Derived {
int an_int;
};
В этом случае, когда вызывается delete Base
, у компилятора есть все основания (из-за правила, которое вы указали в начале вашего вопроса), полагать, что размер данныхуказывает на 1, а не 4. Если он, например, реализует версию operator new
, которая имеет отдельный массив, в котором 1-байтовые объекты все плотно упакованы, и другой массив, в котором 4-байтовые объекты все плотно упакованы,в конечном итоге он будет предполагать, что Base *
указывает куда-то в 1-байтовом массиве сущностей, хотя на самом деле он указывает где-то в 4-байтовом массиве сущностей, и по этой причине совершает всевозможные интересные ошибки.
Я действительно хотел бы, чтобы operator delete
был определен так, чтобы он также принимал размер, и компилятор передавал либо статически известный размер, если operator delete
был вызван для объекта с не-виртуальным деструктором, либо известный размер фактического существа, являющегося объектом.указывает на то, вызывается ли он в результате действия virtual
деструктора.Хотя это, вероятно, будет иметь другие негативные последствия и, возможно, не очень хорошая идея (например, если есть случаи, когда operator delete
вызывается без вызова деструктора).Но это сделало бы проблему до боли очевидной.