Подтвердить что ты не робот

Почему среда выполнения не может применить удаление или удаление [] вместо программиста?

Я читал, что нужен оператор delete[], потому что среда выполнения не сохраняет информацию о том, является ли выделенный блок массивом объектов, которым требуются вызовы деструктора или нет, но фактически хранит информацию о том, где в памяти является выделенным блоком, а также, конечно, размером блока.
Для того, чтобы помнить, нужно ли деструкторов вызывать на удаление или нет, потребуется еще один бит метаданных, поэтому почему бы просто не сделать это?

Я уверен, что есть хорошее объяснение, я не спрашиваю об этом, я просто хочу это знать.

4b9b3361

Ответ 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/С++ - довольно большой прыжок в сложности/абстракции. Помимо всего прочего, добавление этих накладных расходов для каждого объекта приведет к ограничению некоторых подходов к управлению памятью, которые разработаны, зная, что такое размер объектов.