last day (15 days later) » 

22:38
2
Q: Висячие указатели

Matrin-Idenint* ptr = new int(10); std::cout << "Адрес при создании " << ptr << "\n"; delete ptr; std::cout << "Адрес после очистки " << ptr << "\n"; После очистки памяти, на которую ссылался указатель его нужно занулить (ptr = nullptr), чтобы он не ссылался на недействительную область памяти, я ведь прави...

Это по желанию. Кто-то делает это из соображений безопасности. Иногда это технически невозможно, если, например, вы удаляете const int*. Удалить можно, а обнулить нельзя. Иногда, это нужно, если вы хотите использовать указатель снова и опасаетесь ошибок.
Его просто не надо использовать. Зануление - это уже дискуссии про плохой/хороший стиль в клубе любителей ручного управления памятью.
Адрес после delete печатать запрещено. Это странно, но это так. Неопределённое поведение. Вы вообще ничего не можете сделать с ptr, кроме присвоения нового значения.
Нет, после удаления объкта, на которой тот указывал, указатель занулять не обязательно. И хранящийся в нем адрес можно печатать без проблем. delete с самим указателем ничего не делает. Нельзя только разыменовывать. А вообще используйте умные указатели вместо ручного удаления.
Если хотите печатать адрес после очистки скопируйте его до очистки в intptr_t и печатайте копию.
22:38
@StanislavVolodarskiy "Адрес после delete печатать запрещено." - вы с чем-то путаете. Укаазателю можно присвоить какой угодно невалидный адрес и печатать без проблем.
@user7860670, обращение к адресу удалённого объекта - неопределённое поведение. Компилятор имеет право менять это значение во время удаления. И даже делает это в MSVC.
@user7860670, присвоение указателю невалидного адреса - тоже UB. К сожалению, так.
@StanislavVolodarskiy Неопределенное поведение - только разыменование адреса удаленного объекта.
@user7860670, я тоже так думал, зову wololo.
@wololo, требуется ваша помощь.
@StanislavVolodarskiy Но ведь "запрещено" и UB - это не синонимы.
@StanislavVolodarskiy Ну, была бы это функция типа destroy(T*&otr), было бы понятно. Но изменение переданного указателя в delete ptr; — это уже, грубо говоря, нарушение стандарта языка. А как он будет менять, например, delete 0x1234;?
@StanislavVolodarskiy Скажем так, в стандарте не сказано ни об изменении указателя, ни о том, что нельзя обращаться к переменной, содержащей невалидный указатель, с чем-то, кроме разыменования. Т.е. такое поведение в стандарте не описано (если я неправ, не могли бы вы указать соответствующий пункт?).
22:38
@user7860670, MSVC 2012 меняет адрес в удаляемом указателе: stackoverflow.com/questions/33374483/…
@Harry, в C++ 11 обращение к адресу после удаления UB, с C++ 14 "implementation-defined behavior": stackoverflow.com/questions/43508771/…
@CrazyElf, если говорить о стандартном С++ без обращения к особенностям конкретного компилятора, но UB и "нельзя" для меня одно и то же. Как можно рассуждать о программе, которая может делать что угодно? Конечно такую программу нельзя писать и нельзя ею пользоваться. Нельзя. А если вы пишете для GCC, и ставите соответствующие флажки, то можно. Но это уже не стандартный C++.
@StanislavVolodarskiy В C++20 есть только "If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (6.8.2), the deallocation function shall deallocate the storage referenced by the pointer, ending the duration of the region of storage." (6.7.5.4.2.5) Ни о каком implementation-defined behavior речь не идет... В С++17 тоже. Более старых стандартов под рукой нет... Но, кстати, интересно - поскольку любое значение теоретически можно рассматривать как адрес, может быть любая ерунда из-за чего-то типа int x = int((int*)50 - (int*)20);?
@StanislavVolodarskiy Да, я что-то забыл про опцию /sdl, там санитайзер действительно начинает менять указатель по удаления и в актуальной VS2022. Но вот то, что чтение значения указателя после удаления является implementation-defined behavior - это еще не криминал. Ведь печать указателя посрдством перегруженного оператора << или преобразование в uintptr_t (даже когда указатель указывает на живой объект) - все тоже является implementation-defined behavior.
@Harry После освобождения памяти указатель становится невалидным. Разыменование и повторное освобождение памяти вызывают UB, любое иное использование невалидного указательного значения вызывает implementation-defined behavior. В последних версиях черновика стандарта см. пункт basic.compound / 4. operator<< преобразует указатель в некоторую последовательность символов, вопрос только в том, что это за последовательность символов. Приведение в uintptr_t тоже делает вполне конкретную вещь — создаёт некоторое целочисленное значение...
...(причём, если его привести в исходный указательный тип, то мы получим исходное указательное значение), вопрос только в том, какое отображение используется между указательными типами и uintptr_t. Если же мы прочтём невалидный указатель, то произойти может... да что угодно может произойти, например, basic.compound 34): Some implementations might define that copying such a pointer value causes a system-generated runtime fault. Это крайне враждебное implementation-defined behavior, совсем не похожее на два предыдущих примера. @user7860670
@StanislavVolodarskiy ...
@wololo, большое спасибо! Жаль что вы не пишете ответы, вашей экспертизы не хватает на ruSO.
@wololo Насколько я могу судить, начиная с C++17 это "Some implementations might define..." из стандарта изъято... Вероятно, никто не воспользовался :)

last day (15 days later) »