Тут я как всегда не вовремя задумался вот над каким вопросом. При выделении памяти из кучи очевидно, что в куче должна сохраняться информация о размере запрошенной области памяти и о количестве запрошенных элементов. Зачем же тогда существуют отдельно операторы delete и delete[]? Ведь независимо от того, запросили мы вектор или один элемент, в куче есть информация и о размере запрошенной области, и о количестве запрошенных элементов. Не может быть, чтобы при запросе одного элемента в куче не сохранялась информация о том, что запрошен один элемент. А если это так, то оператор delete вполне может разобраться (по служебной информации, содержащейся в куче) был ли запрошен массив или был запрошен один элемент. И, соответственно, вернуть в кучу память или одного элемента, или вектора. Получается, что оператор delete[] избыточен. UPD1: В нынешнем подходе С++ поступает более экономично: хранит свою дополнительную информацию только в массивах объектов с нетривиальным деструктором. То есть Вы хотите сказать, что у кучи есть несколько форматов? Один формат для запрошенного одного элемента, другой формат для запрошенного вектора, третий формат для запрошенного одного элемента с нетривиальным аллокатором/деструктором, четвертый формат для запрошенного вектора с нетривиальным аллокатором/деструктором? Ну, это дело конечно разработчиков компилятора и кучи, как там они видят свою задачу чтобы сделать ее максимально эффективной. Но на первый взгляд иметь много форматов кучи это не так чтобы однозначно было эффективнее, чем хранить всю информацию и в рантайме разбираться, что же именно там сейчас лежит. Тем более, что разбираться в рантайме и при подходе со многими форматами кучи все равно придется. UPD2: И да, нетривиальный аллокатор тоже хранит в куче информацию о количестве запрошенных элементов и о размере одного элемента. Имея эту информацию нетривиальный деструктор может разобраться, что именно ему надо удалять. И опять же в этом случае не нужен оператор delete[], достаточно оператора delete. UPD3: Оставим пока в покое нетривиальные аллокаторы. Рассмотрим пока что стандартные аллокаторы, тем более что проблемы в обоих случаях одинаковы. Итак, есть куча и есть операторы new и new[]. Оба оператора обязаны занести в служебную информацию кучи данные о размере одного объекта и о КОЛИЧЕСТВЕ ОБЪЕКТОВ в запросе. Соответственно, оператор возврата памяти delete нужен только один, так как по служебной информации рантайм может и должен разобраться сколько именно объектов было запрошено. Соответственно, оператор delete[] избыточен. Теперь рассмотрим нестандартные (пользовательские) аллокаторы. Совершенно так же пользовательские new и new[] обязаны занести в служебную информацию кучи данные о размере одного объекта и о КОЛИЧЕСТВЕ ОБЪЕКТОВ в запросе. Дополнительно пользовательские new и new[] обязаны занести в служебную информацию кучи указатель на пользовательский деструктор. Опять же в этом случае оператор возврата памяти delete нужен только один, так как по служебной информации рантайм может и должен разобраться сколько именно объектов было запрошено. Соответственно, оператор delete[] избыточен.
Ответ Во-первых, даже если в куче и сохраняется информация о размере запрошенного блока в байтах, способ хранения этой информации может быть известен delete только в том случае, если используется "штатный" аллокатор. Но процесс выделения "сырой" памяти в С++ является перегружаемым пользователем. Как только выделение памяти перешло на пользовательский аллокатор, delete уже не может определить размер блока. Во-вторых, даже если размер блока в байтах известен, по этому размеру все равно нельзя однозначно восстановить точное количество элементов в массиве, чтобы вызвать точное количество деструкторов. Размер блока может превышать точное значение, требуемое для хранения элементов. В-третьих, не ясно, о каком "количестве запрошенных элементов" вы говорите. Количество запрошенных элементов сохраняет именно new [] и вычитывает именно delete []. Для того, собственно, delete [] и сделан отдельным от delete. Смотрите детали здесь: Откуда C/C++ знает сколько надо освободить памяти, если не знает размер массива? Теоретически можно сделать "умный delete", который сам всегда во всем разбирается. Но это приведет к безусловной необходимости хранить дополнительную информацию во всех блоках памяти. В нынешнем подходе С++ поступает более экономично: хранит свою дополнительную информацию только в массивах объектов с нетривиальным деструктором. Фактически почти такой "умный delete" у вас уже есть. Никто вам не запрещает везде просто безусловно пользоваться new[]/delete[] и забыть про существование new/delete. То есть одиночные объекты просто выделять как массивы размера 1. Но это будет несколько более расточительно (и не поддерживает полиморфного удаления).
Отвечая на ваш UPD1: В типичной реализации у блока в С++ куче фактически три формата: для одиночного объекта (new), для массива с тривиальными деструкторами (new[]) и для массива с нетривиальными деструкторами (new[]). При этом первые два формата можно было бы считать совпадающими с точки зрения внутренней структуры, т.к. это просто "блоки памяти". Но тут вмешивается тот факт, что механизмы выделения/освобождения "сырой" памяти в С++ являются перегружаемыми пользователем: независимо для new/delete и для new[]/delete[]. Поэтому это - отдельные форматы.
Ответ на ваш UPD3: Я не знаю, с чего вы взяли, что "Оба оператора обязаны занести в служебную информацию кучи данные о размере одного объекта и о КОЛИЧЕСТВЕ ОБЪЕКТОВ в запросе". Это совершенно не так. Еще раз: просто new такой информации НЕ сохраняет. И new[] для типов с тривиальным деструктором никакой информации о количестве или размере объектов НЕ хранит тоже. Эти форматы просто выделяют память через обычный malloc, освобождают через обычный free и никакой дополнительной внутренней информации в этом блоке памяти не сохраняют. С точки зрения С++ памяти требуется ровно столько, сколько нужно для хранения пользовательских данных. Особняком стоит только new[] для массива с нетривиальными деструкторами. Только он сохраняет в блоке служебную информацию о точном количестве элементов в массиве (и поэтому выделяет несколько больше памяти, чем требуется для пользовательских данных). Информация о размере одного элемента в таком блоке не хранится вообще никогда - это низачем не нужно. Я при этом говорю только о стандартных аллокаторах. Пользовательские аллокаторы тут ни при чем.