C ++: динамически размещенные переменные не удаляются в Clang - PullRequest
0 голосов
/ 24 апреля 2018

«Решение проблем с C ++, 9-е издание» Уолтера Савича на стр. 517:

Когда вы применяете delete к переменной указателя, динамическая переменная, на которую она указывает, уничтожается. В этот момент значение переменной указателя не определено, что означает, что вы не знаете, куда она указывает, и каково значение, на которое она указывает. Более того, если какая-то другая переменная-указатель указывала на динамическую переменную, которая была уничтожена, то эта другая переменная-указатель также не определена.

Однако, похоже, что при clang-902.0.39.1 удаление указателя не мешает мне использовать переменную. Вот короткий пример, демонстрирующий это поведение:

int *p1, *p2;
p1 = new int(3);
p2 = p1;

cout << *p1 << endl << *p2 << endl;

delete p1;

cout << *p1 << endl << *p2 << endl;

Используя этот код, у меня есть вывод 4 3 с в отдельных строках. Я ожидаю, что при ссылках на p1 и p2 после delete p1; произойдет ошибка, не так ли?

В компиляторе Visual Studio C ++ ссылка p2 выводит большое отрицательное число, указывающее, что мы ссылаемся на не принадлежащую нам память, а доступ к p1 вызывает сбой программы.

Ответы [ 4 ]

0 голосов
/ 24 апреля 2018

Память была освобождена, но ваши указатели все еще указывают на то место, где раньше были данные.

0 голосов
/ 24 апреля 2018

Эта память все еще там, когда вы удаляете указатель, и указатель по-прежнему указывает на него. Однако у вас нет никаких гарантий, что он все еще будет действителен или что он все еще будет существовать в будущем. Распределение памяти (new / malloc / etc) пометило это место в памяти как больше не используемое, поэтому оно может перераспределить его или освободить всю память на страницах, и в этот момент доступ к ней приведет к нарушению доступа (выдаёт ошибку сегментации).

Например, если я создам три новых типа, используя указатели, они, вероятно, будут помещены рядом друг с другом в память. Если я удаляю средний указатель, его адрес все еще действителен, поскольку страница памяти не может быть освобождена, пока вся память для него больше не будет недействительной. Однако, хотя я могу получить доступ к памяти для теперь удаленного указателя, я не должен. Это потому, что если я создам новый указатель типа int, он, вероятно, будет назначен этому новому месту.

ПЛОХАЯ МЕТАФОРА: Память как места в классе. Некоторые люди нуждаются в большем количестве сидений (или поднимают ноги или кладут сумку), а некоторым - меньше. Вы не можете удалить класс из школы, пока все места в этом классе не освободятся. Если вы попросите назначить место, вы можете получить номер 1, место 2. Если вы откажетесь от этого места (например, удалите указатель), вы все равно можете обратиться к room1 / seat2, даже если оно больше не ваше. Если вы попытаетесь сидеть в нем, вы можете обнаружить, что кому-то еще это уже было назначено. Если вы сидите в нем, классная комната может быть закрыта в любое время, потому что вы сказали, что закончили с вашим местом.

seat = память, на которую указывает указатель

класс = страница памяти

0 голосов
/ 24 апреля 2018

Я ожидаю, что ошибка произойдет при ссылке на p1 и p2 после удаления p1; не так ли?

Не обязательно.

При этомточка, значение переменной-указателя не определено

Не определено, например, использование указателя после вызова delete может привести к чему-либо: хорошему, плохому или нейтральному.

Компилятору не требуется устанавливать какие-либо барьеры времени выполнения для дальнейшего использования указателя.В частности, не требуется немедленно завершать программу.Конечно, хороший компилятор (с правильными настройками) может предупредить вас, если увидит, что ваш код повторно использует удаленные указатели.

В компиляторе Visual Studio C ++ ссылка на p2 выводит большое отрицательное число, указывая, что мыобращение к памяти, которая не принадлежит нам, и доступ к p1 вызывает сбой программы.

Определенный компилятор может создать процесс, который в конкретной операционной системе при определенных условиях загрузки памяти вызываетавария.Или не может.Точно так же не требуется, чтобы память, связанная с указателем, была заполнена мусорными данными.

В частности, я считаю, что Visual Studio в отладочной сборке может обрабатывать память указателя, так что дальнейшее использование приводит к сбою/ исключение.Это полезно для возможности отладки.

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

  • Процесс освободил память для операционной системы.Ваша программа пытается получить доступ к памяти, к которой у нее нет прав.SEGFAULT (сбой).
  • Внутренне память помечена как принадлежащая другой переменной (т. Е. Какой-то другой части вашей программы с именем new или аналогичной) и была записана в нее.Возможно, он заполнен данными для мусора.Может возникнуть или не возникнуть проблема в зависимости от того, как ваша программа использует переменную.Может произойти сбой, распечатать искаженный текст и т. Д.
  • Внутренне память помечена как удаленная, но никакой другой части вашей программы это не требуется.На данный момент память осталась нетронутой.Предположительно, это то, что вы видели в clang.

Короче говоря, предсказать, что будет с памятью для удаленного указателя, сложно, единственная ответственность, которая дается программисту, такова: не использоватьэто снова.

0 голосов
/ 24 апреля 2018

Ваши указатели все еще указывают на старую позицию, просто эта память больше не принадлежит им. Позже могут быть другие данные. Так что это не стабильный вывод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...