Почему среда выполнения не может применить удаление или удаление [] вместо программиста?
Я читал, что нужен оператор delete[]
, потому что среда выполнения не сохраняет информацию о том, является ли выделенный блок массивом объектов, которым требуются вызовы деструктора или нет, но фактически хранит информацию о том, где в памяти является выделенным блоком, а также, конечно, размером блока.
Для того, чтобы помнить, нужно ли деструкторов вызывать на удаление или нет, потребуется еще один бит метаданных, поэтому почему бы просто не сделать это?
Я уверен, что есть хорошее объяснение, я не спрашиваю об этом, я просто хочу это знать.
Ответы
Ответ 1
Здесь нужно прояснить две вещи.
Во-первых: предположение, что malloc
сохраняет точный размер, который вы задали.
Не совсем. malloc
заботится только о том, чтобы обеспечить достаточно большой блок. Хотя по соображениям эффективности он, вероятно, не будет зацикливаться, скорее всего, даст вам блок "стандартного" размера, например блок 2^n
bytes. Поэтому реальный размер (как и число фактически выделенных объектов) фактически неизвестен.
Второе: требуется "дополнительный бит"
Действительно, информация, требуемая для данного объекта, чтобы знать, является ли он частью массива или нет, будет просто дополнительным битом. Логически.
Что касается реализации, то: где бы вы на самом деле положили этот бит?
Память, выделенная для самого объекта, вероятно, не должна быть затронута, объект использует ее в конце концов. Итак?
- на какой-то платформе это можно сохранить в самом указателе (некоторые платформы игнорируют часть бит), но это не переносится
- поэтому для этого потребуется дополнительное хранилище, по крайней мере байт, за исключением того, что при проблемах выравнивания он может составлять до 8 байтов.
Демонстрация: (не убедительно, как отмечено sth, см. ниже)
// A plain array of doubles:
+-------+-------+-------
| 0 | 1 | 2
+-------+-------+-------
// A tentative to stash our extra bit
+-------++-------++-------++
| 0 || 1 || 2 ||
+-------++-------++-------++
// A correction since we introduced alignment issues
// Note: double aligment is most probably its own size
+-------+-------+-------+-------+-------+-------
| 0 | bit | 1 | bit | 2 | bit
+-------+-------+-------+-------+-------+-------
Humpf!
ИЗМЕНИТЬ
Поэтому на большинстве платформ (где адрес имеет значение) вам нужно "расширить" каждый указатель и фактически удвоить их размеры (проблемы выравнивания).
Допустимо ли, что все указатели будут в два раза больше, только чтобы вы могли занести этот дополнительный бит? Для большинства людей, я думаю, это было бы. Но С++ не предназначен для большинства людей, он в первую очередь предназначен для людей, которые заботятся о производительности, скорости или памяти, и, как таковая, это неприемлемо.
КОНЕЦ РЕДАКТИРОВАНИЯ
Итак, каков правильный ответ? Правильный ответ заключается в том, что восстановление информации, потерянной системой типа, является дорогостоящим. К сожалению.
Ответ 2
Я думаю, причина в том, что С++ не заставляет вас во что-то, чего вы не хотите. Он добавил бы дополнительные метаданные, и если кто-то не использовал его, дополнительные накладные расходы были бы навязаны им, в отличие от целей дизайна языка С++.
Когда вам нужна описанная вами возможность, С++ действительно обеспечивает способ. Он называется std::vector
, и вы почти всегда предпочитаете его, другой вид контейнера или умный указатель на raw new
и delete
.
Ответ 3
С++ позволяет вам быть максимально эффективными, поэтому, если им нужно отслеживать количество элементов в блоке, которые будут просто лишними 4 байтами, используемыми для каждого блока.
Это может быть полезно многим людям, но также предотвращает общую эффективность для людей, которые не возражают против ввода [].
Это похоже на разницу между С++ и Java. Java может быть намного быстрее, потому что вам никогда не придется беспокоиться о сборке мусора, но С++, если он запрограммирован правильно, может быть более эффективным и использовать меньше памяти, потому что ему не нужно хранить какие-либо из этих переменных, и вы можете решить, когда удалите блоки памяти.
Ответ 4
Это в основном сводится к языковому дизайну, не желающему вводить слишком много ограничений для разработчиков. Во многих сценариях С++ для ::operator delete ()
используется malloc()
для ::operator new ()
и free()
(более или менее). Стандартные malloc
/free
не предоставляют бухгалтерский учет, необходимый для записи ряда элементов, и не дают возможности определить размер malloc
'd в free
. Добавление другого уровня манипуляции с памятью между new Foo
и malloc
для каждого отдельного объекта - с точки зрения C/С++ - довольно большой прыжок в сложности/абстракции. Помимо всего прочего, добавление этих накладных расходов для каждого объекта приведет к ограничению некоторых подходов к управлению памятью, которые разработаны, зная, что такое размер объектов.