LINUX.ORG.RU

intro.execution/6 + basic.stc/4 = ?

 ,


0

0

[intro.execution]p6 заявляет, что «An instance of each object with automatic storage duration is associated with each entry into its block. Such an object exists and retains its last-stored value during the execution of the block»

[basic.stc]p4 заявляет, что «When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values.»

В коде

int main()
{
	auto pi = new int{};
	delete pi;
}

Каково будет значение указателя pi после выполнения delete pi? Результат new-expression, а значит и изначальное значение pi, это pointer to object. Согласно [intro.execution]p6 объект должен содержать last-stored value. Согласно [basic.stc]p4, освобождение памяти меняет значение указателя на invalid pointer value. Значит ли, что освобождение памяти приводит к записи (store) в переменную-указатель?

P.S. Шизофреникам, для которых «became invalid pointer value» это «не изменилось»:

Every value of pointer type is one of the following:
— a pointer to an object or function (the pointer is said to point to the object or function), or

— an invalid pointer value.

Надеюсь, «one of the following» ясно даёт понять, что значение не может стать invalid pointer value и при этом оставаться pointer to an object.

Значение указателя - адрес - не изменится. Просто по данному адресу уже будет область памяти не помеченная как аллоцированная под что-то, поэтому работать с ней нельзя.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)

«became invalid pointer value» это «не изменилось»

Так. Сам ты шизофреник. Указатель перестал указывать на существующий объект, значит он invalid.

ox55ff ★★ ()
Ответ на: комментарий от ox55ff

Так. Сам ты шизофреник.

Почему?

Указатель перестал указывать на существующий объект, значит он invalid.

Но как могло измениться его значение, если он должен был retain its last-stored value?

vectorisation ()
Ответ на: комментарий от vectorisation

Но как могло измениться его значение

Его значение не изменилось. Изменилось то, на что он указывал. Память была освобождена и больше туда по указателю ходить не надо.

ox55ff ★★ ()
Ответ на: комментарий от vectorisation

Вот ну очень упрощенная схема без заморочек типа heap, stack и т. п. (да простят меня знатоки)

Ячейки памяти
Адрес:      1   2   3   4   5   6
Значение:   ?   ?   ?   ?   ?   ?

Код:
int a;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   ?   ?   ?   ?   ?   ?
Компилятор ассоциирует переменную a с адресом 1

Код:
a = 9;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   9   ?   ?   ?   ?   ?

Код:
int *p;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   9   ?   ?   ?   ?   ?
Компилятор ассоциирует переменную p с адресом 2

Код:
p = new int;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   9   5   ?   ?   ?   ?
За программой закреплено 3 ячейки памяти: 1 (для a), 2 (для p), 5 (выделенная динамически)

Код:
*p = 8;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   9   5   ?   ?   8   ?

Код:
delete p;
Результат:
Адрес:      1   2   3   4   5   6
Значение:   9   5   ?   ?   8   ?
За программой закреплено 2 ячейки памяти: 1 (для a), 2 (для p).
Ячейка 5 может быть выделена другой переменной с помощью new, или даже другой программе. 

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от vectorisation

Ты занимаешься буквоедством. Указатель - число. Число понимается как адрес, по которому лежит что-то, на что указывает указатель.

Короче к чёрту всё.

ox55ff ★★ ()
Ответ на: комментарий от ox55ff

Ты занимаешься буквоедством.

Ну да, я знаю.

Указатель - число. Число понимается как адрес, по которому лежит что-то, на что указывает указатель.

Это описание «типичной» реализации и только.

Короче к чёрту всё.

Стандарт C++ не для слабонервных, это да.

vectorisation ()
Ответ на: комментарий от vectorisation

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

ox55ff ★★ ()
Ответ на: комментарий от ox55ff

Фишка в том, что уже написано куча кода на цпп. И никто в стандарт не будет вносить изменения, которые сломают это поведение.

Некуда ломать, оно сейчас сломано. Насколько мне известно, планируется починка этого поведения.

vectorisation ()
Ответ на: комментарий от vectorisation

Ок, если хочешь, давай с такой стороны.

За программой закреплены определённые участки памяти. Они могут быть как статические, так и динамические. Статические выделяются при запуске программы; это области памяти под переменные, которые ты объявил в программе. Динамические - ты их выделяешь и освобождаешь с помощью new и delete.

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

Указатель - число, адрес ячейки памяти. Невалидный указатель содержит адрес ячейки, которая не закреплена за программой.

Получается, что когда ты выделяешь память с помощью new, программа находит свободную ячейку памяти и закреляет ее за собой; адрес этой ячейки помещается в переменную-указатель. Указатель валидный. Когда ты делаешь delete, программа помечает ячейку памяти как свободную, не закрепленную за собой. И хотя численное значение указателя не меняется, получается что указатель не валидный, так как указывает на ячейку памяти уже не закрепленную за программой.

Так понятней?

Опять же, на практике всё гораздо сложнее, но для начала такой модели мира хватит.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 3)
Ответ на: комментарий от vectorisation

Вот еще на подумать:

#include <stdio.h>

int main()
{
  char *p;
  char a[] = {10, 11, 12};

  printf("p = %x\n", (int)p );

  p = &a[0];

  printf("p = %x -> %d \n", (unsigned int)p, (int)(*p)  );
  p++;
  printf("p = %x -> %d \n", (unsigned int)p, (int)(*p)  );
  p++;
  printf("p = %x -> %d \n", (unsigned int)p, (int)(*p)  );

  return 0;
}

Результат:
p = 4bb9e060
p = a2300525 -> 10
p = a2300526 -> 11
p = a2300527 -> 12

Kroz ★★★★★ ()
Ответ на: комментарий от vectorisation

Вот смотри:

int *a = new int {777};
int *b = a;
delete a;
Ты хочешь, чтобы после delete значения у «a» и «b» изменились? Ну ладно «a», оператор delete может это сделать. Присвоить nullptr, например. Но как он до «b» доберётся? Рантайм должен поддерживать реестр всех указателей? Это же будет тормозное говно.

ox55ff ★★ ()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Ты хочешь, чтобы после delete значение у «a» и «b» изменились?

Это стандарт хочет :/

Но как он до «b» доберётся? Рантайм должен поддерживать реестр всех указателей?

Для обычных указателей можно ничего не делать, т.к. была в него запись invalid p. v. или не была — неотличимо.

А с volatile указателями возникают проблемы, т.к. запись в volatile объекты это наблюдаемое поведение, которое реализация абстрактной машины должна сохранять.

(Проблемы много с чем, кроме volatile, но пока хватит.)

vectorisation ()
Ответ на: комментарий от shdown

Начнём с того, что обсуждается C++, а твой код в режиме C++ не компилируется на x86-64 ни gcc, ни clang.

Потому что компиляторы нынче шибко умные стали. Мне пришлось указать -fpermissive чтобы компилятор разрешил выстрелить в ногу.
Но UB не вижу. Вижу только преобразование типов с потерей точности. В чём UB?

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от shdown

То, что значение указателя - это адрес ячейки памяти. C этим значением можно производить арифметические операции как и с любым числом. Увеличив значение указателя на 1 можно обратиться к следующей ячейке памяти (в данном случае - к следующему элементу массива).

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 2)
Ответ на: комментарий от Kroz

Но вопрос в топике про стандарт. В стандарте не определено, что «значение указателя - это адрес ячейки памяти». Это особенность этой реализации, частного случая.

Согласно стандарту, с указателем нельзя производить «арифметические операции как и с любым числом»; например, само вычисление `(a + 4)`, где `a` — массив из трёх элементов, — UB.

shdown ()
Ответ на: комментарий от shdown

Вопрос в топике «Каково будет значение указателя pi после выполнения delete pi?», и как может быть одновременно «Значение не меняется» и «указатель становится невалидным».
И потом ТС не верил что переменная указатель де-факто содержит адрес.
Я разъяснил обе эти вещи.

Kroz ★★★★★ ()
Ответ на: комментарий от vectorisation

Я не не верил, а сказал, что меня не интересуют детали реализаций.

Тогда в чём вопрос?

Каково будет значение указателя pi после выполнения delete pi?

В стандарте не специфицируется.
Де-факто не меняется.

Результат new-expression, а значит и изначальное значение pi, это pointer to object. Согласно [intro.execution]p6 объект должен содержать last-stored value. Согласно [basic.stc]p4, освобождение памяти меняет значение указателя на invalid pointer value.

Нет, не меняет. Просто указатель становится не валидным. Он начинает указывать на область памяти, которая больше не принадлежит программе. Де-факто меняется принадлежность области памяти к программе, а не значение указателя.

Значит ли, что освобождение памяти приводит к записи (store) в переменную-указатель?

В стандарте не специфировано.
Де-факто нет.

Kroz ★★★★★ ()
Ответ на: комментарий от vectorisation

[basic.stc]/4

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values.

Ты различаешь "становится не-валидным" и "меняется на не-валидный"?

В [basic.stc]/4 нигде не написано что он меняется. И де-факто он не меняется. Но он становится не-валидным, потому, как, хоть его значение не меняется, он начинает указывать на область памяти, которая больше не принадлежит программе. На практике меняется аттрибут памяти - принадлежность к программе, занято/свободно.

У меня синий цвет может стать нелюбимым. И хоть сам синий цвет не поменяется, так и останется синим, но моё отношение к этому цвету может поменяться, и тогда цвет станет нелюбимым.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 5)
Ответ на: комментарий от Kroz

Ты различаешь «становится не-валидным» и «меняется на не-валидный»?

В [basic.stc]/4 нигде не написано что он меняется.

О, шиза попёрла…

Если значение указателя было A, а в результате некоего события стало B (причём B отличается от A), то значение указателя поменялось. По обычному человеческому определению слова «поменялось».

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

Это особенности какой-то (каких-то) реализации(й), в которых становление указателя невалидным может выражаться в выставлении каких-то атрибутов страницам памяти или в чём-нибудь подобном. Меня не интересуют особенности реализаций, я уже не первый раз сообщаю.

vectorisation ()
Ответ на: комментарий от Kroz

Не нравится слово «поменялось», его можно убрать.

Одно место в стандарте говорит, что объект сохраняет последнее записанное значение, другое говорит что значение при освобождении становится таким-то (отличным от того, которым было до освобождения). Раз оно стало другим, значит это значение было записано туда. Иначе будет противоречие с пунктом, который говорит о сохранении последнего записанного.

Так ок?

vectorisation ()
Ответ на: комментарий от vectorisation

Если значение указателя было A, а в результате некоего события стало B (причём B отличается от A), то значение указателя поменялось. По обычному человеческому определению слова «поменялось».

Указатель не поменялся. Просто с точки зрения операционной системы изменилось состояние памяти по указателю.

Это как адрес дома. Дом снесли, а адрес дома в твоём справочнике никуда не делся. Изменилось состояние дома, а не его адрес.

anonymous ()