Если тип данных указателя такой же, как у вновь введенных данных, я думаю, что это не приведет к ошибке, но если указатель имеет другой тип данных, у нас будет несоответствие типов. Мне было интересно, будет ли компилятор что-то делать с этим (скажем, сначала удалить висячий указатель) или просто выдаст ошибку.
@YuHao абсолютно прав.
если ты delete
Во-первых, вы можете получить ошибку сегментации, если она отображает страницу, которая ранее существовала в адресном пространстве вашего процесса.
В любом другом случае вы просто записываете данные куда-то; к тому времени, когда вы это сделаете, там может быть что-то полезное. В любом случае, вы должны избегать этого.
Мне было интересно, будет ли компилятор что-то делать с этим (скажем, сначала удалите висячий указатель)
Мог сделать (не буду)
или просто дать ошибку.
Мог сделать (не буду)
Это свисающий указатель. Там нет защиты от этого.
Это неопределенное поведение. Это принципиально неопровержимо.
Возможно, краткий обзор, поэтому мы на одной странице поможем.
Давайте предположим, что современный ПК с многозадачной ОС, такой как Linux.
Когда запускается программа на C ++, создается процесс, который имеет личное пространство памяти. Это линейное отображение адресов, которые ЦП и ОС переводят в реальные адреса в ОЗУ.
C ++ — это строго типизированный низкоуровневый язык с ручным управлением памятью. Строго типизированный означает, что компилятор выполняет некоторые базовые проверки, чтобы убедиться, что логические утверждения в вашей программе имеют смысл. Указатели — это просто другой тип.
Например:
float f = 10.0f; // this is ok, 10.0f is a float literal
float* pF = &f; // types match, & operator returns type float*
int i = f; // types do not match. Compiler error or warning.
int* i = pF; // types do not match, int* is not float*
float f2 = pF; // types do not match, float is not float*
и так далее.
Это время компиляции. Это действительно так. После запуска программы среда выполнения C ++ становится довольно тупой. Он не выполняет слишком много проверок операций с памятью, поскольку они могут замедлить работу программы, и философия C ++ заключается в том, что «если вы не просили об этом, вы не платите за это».
При этом самая фундаментальная наша память — это просто последовательность байтов. Типы данных, такие как float и int, являются многобайтовыми типами данных (4 байта для 32-битных платформ). Это означает, что число с плавающей запятой хранится в 4 смежных байтовых слотах.
Наконец, мы готовы ответить на ваш вопрос. Если вы выделяете память во время выполнения через что-то вроде new
Вы возвращаете указатель на память, которую можете использовать. Скажем, мы делаем это для одного поплавка. new
знает, как пометить эту память как «используемую». new
не даст указатель на эти 4 байта кому-либо еще, так что вы в безопасности. Когда вы вызываете delete
это возвращает память обратно в кучу — некоторая другая часть вашей программы может выделить ее позже. Но указатель у вас нет изменений. Мы все еще можем использовать указатель для записи в память, только теперь мы находимся в беде.
Пример:
float *pF = new float; // allocate 4-bytes on a 32-bit system
*pF = 10.0f; // fine
delete pF; // free the memory
*pF = 20.0f; // ?????
Эта последняя инструкция говорит: «запишите 20.0f в память, на которую указывает pF». Мы больше не «владеем» этой памятью. Мы говорим, что этот указатель болтается, поскольку он не указывает на действительную память, в которую мы можем безопасно писать. Но это указывает на доступную для записи память. Вы правы, что это источник ошибок.
Существуют распределители памяти C ++, которые записывают в память специальные значения, чтобы указать, неинициализирован ли он или был ранее удален. Это будет зависеть от вашей ОС и набора инструментов.
Еще один вариант, чтобы найти такие ошибки, это использовать удивительный инструмент Valgrind который будет имитировать память вашей программы и помечать ошибки такого рода.