Почему удаление может выполняться по указателям на const, а бесплатно - нет?

Я только заметил, что указатели, переданные в delete, могут быть const квалифицированными, а те, которые переданы в free, не могут. Это действительно сюрприз для меня.

И в С++ перегрузка на operator delete должна иметь подпись, например:

void operator delete(void* p);

Но добавление указателя const к указателю параметра недействительно:

void operator delete(void const* p);

Может кто-нибудь сказать мне, почему delete разработан таким образом?

Ответ 1

free не следует использовать с реальными объектами С++. free следует использовать с malloc, поэтому вы не должны использовать free для того, что вы выделили с помощью new.

Что касается причин, по которым вы можете delete const-объекты, это просто:

const Type *ptr = new Type(...);

Теперь что? Если вы не можете удалить это, вам нужно будет сделать это:

delete const_cast<Type*>(ptr);

Наличие объекта const означает, что его нельзя изменить. Вы не можете заставить объект перейти из одного состояния в другое. Удаление удаляет его. Это означает, что он больше не существует в каком-либо состоянии, будь то оригинал или какая-либо другая модифицированная форма. Удаление - это операция, которая существует вне состояния изменчивости объекта, подобно построению.

Концептуально удаление не является ни константой, ни константой. Хотя деструктор является неконстантной функцией, идея разрушения объекта просто выходит за пределы константы const или не const.


ОК, скажем, вы определяете operator delete, чтобы взять указатель на const (который отличается от указателя const):

void operator delete(void const* p);

Какова первая строка этой функции? Цель operator delete - освободить память, выделенную operator new. Это потребует выталкивания битов в кучу выделения памяти. И для этого вам нужен указатель, который не указывает на данные const:

void *ptr = const_cast<void*>(p);

Добро пожаловать в undefined поведение. В то время как С++ позволяет это сделать, в спецификации очень ясно, что результаты попыток записи на ptr (или любой адрес на основе этого) undefined. Вы получили указатель на const; вам сказали окружающий мир, чтобы он не изменил то, на что он указал. С++ не дает никаких гарантий относительно того, что происходит, когда вы нарушаете этот контракт.

Поскольку спецификация заявляет, что это поведение undefined, и поскольку operator delete (в большинстве случаев) не может выполнять свою работу без изменения памяти, на которую указывает p (или изменение памяти на основе этого адреса), это было бы глупо из спецификации, чтобы затем дать вам возможность определить operator delete таким образом. В основном это было бы канонизировать идею стрельбы в ногу.

Да, практически в каждом случае это будет абсолютно безопасно. Но так как вы все равно откажетесь от const, почему бы вообще не позаботиться о довольно сомнительной идее?

Ответ 2

free - функция C. Его подпись 20-30 лет, со времен, когда в языке C не было const (и не было языка С++). Компилятор С++ рассматривает free как и любую другую функцию и не может позволить ему принимать указатель const без приведения в действие, потому что free может изменить объект, указанный. На самом деле, это так же, как и delete, но С++ не знает, что free используется для управления памятью.

Ответ 3

Модификатор const, применяемый к указателю, означает, что указанный объект не будет изменен.

Однако delete выводит объект навсегда из обращения. Никто не заботится о том, что с ним происходит после его удаления. Следовательно, для всех, кого мы знаем, удаление может изменить объект, а может и нет. Почему это имеет значение? Любая попытка прочитать или записать содержимое объекта будет undefined.

С другой стороны, когда вы реализуете свой собственный delete, вам, вероятно, потребуется изменить умирающий объект. Следовательно, нужно, чтобы указатель был не const.

Ответ 4

Одно отличие состоит в том, что free является библиотечной функцией, и вы должны соответствовать типу параметра. Когда free был добавлен на язык C, не было ключевого слова const, поэтому его даже нельзя было рассмотреть.

В С++ delete p это оператор, обрабатываемый компилятором. Он может делать все, что хочет разработчик языка, в том числе не учитывать, указывает ли объект на const или нет.

Философски говоря, оператор delete не изменяет объект, он просто заставляет его уйти.