(создание сообщества-вики, как включение DYP свой комментарий повторно 3,8/7 является очень важным, в то время как мой ранний анализ был правильным, я бы сказал примерно так же вещи о коде, который был сломан, забыв 3,8/7 сам)
Const *q,*p = new Const(1);
new (p) Const(2);
Линия new(p) Const(2);
перезаписывает объект, который был построен с Const(1)
.
memcpy (&q, &p, sizeof p);
Это эквивалентно q = p;
.
cout << q->i;
Это обращается к q->i
элемент, который будет 2
.
В некоторой степени примечательных вещах:
std::memcpy
некрасивый способ назначить p
к q
... это законно, хотя при 3,9/3:
Для любого тривиального копируемого тип T
, если два указателя на T
указывают на отчетливые T
объекты obj1
и obj2
, где ни obj1
или obj2
является подобъектом базового класса, если базовые байты (1,7), составляющие obj1
, копируются в obj2
, obj2
в дальнейшем сохраняют то же значение, что и obj1
. [Пример:
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
Перезапись старого Const(1)
объекта с Const(2)
допускается при условии, что программа не зависит от побочных эффектов деструктора прежнего, который он не делает.
(как DYP отмечено в комментариях ниже) постоянного доступа к Const(2)
объекта с использованием p
является незаконным в соответствии с 3.8/7 в третьем пункте:
указатель, который указывает на исходный объект [... ] может быть использована для манипулирования нового объекта, если ...
- типа исходного объект не
const
-qualified, и, если тип класса, не содержит какой-либо нестатический membe данных г, тип которого является const
-qualified или ссылочный тип ...
- с использованием
q
- а не p
- для доступа к i
предположительно необходимо избегать оптимизаций компилятора на основе предполагаемого знания i
.
Что касается Вашего комментария:
Обратите внимание, что после завершения строительства второго Const
, p
не делает семантически (? Намеренно) указывает на новый объект, а первый нет, поэтому она годна к употреблению " как void*
".
Учитывая вам места размещения нового объекта по адресу, указанному в p
, p
, безусловно, действительно, указывает на вновь созданный объект, и очень намеренно, но он не может быть использован для управления этим объектом при 3,8/7 как указано выше.
Учитывая, что у вас есть понятие «семантически указывая», которое не определено в C++, истинность этой части утверждения в вашем собственном сознании.
«после строительства второй Const
, p
... может использоваться«как void*
» не имеет никакого смысла ... это не более удобным, как и все, чем это было заранее.
Но второй объект построен на тот же адрес, так что битовый образ p
представляет адрес нового объекта.
конечно, но ваши комментарии показывают, вы думаете «немного картины» как-то дис tinct from значение указателя, применимого к присвоению с =
, что неверно.
new (p) Const(2)
Стирание старый объект, хранящийся в p
, поэтому указатель не является действительным больше, кроме как указатель на хранение (void*
).
«стереть» это странный термин для него ... переписывание будет более значимым. Как указано выше и объяснено выше, 3.8/7 говорит, что вы не должны «манипулировать» объектом. p
указывает после нового размещения, но значение и тип указателя не зависят от нового объекта placmeent. Как вы можете позвонить f(void*)
с указателем на любой тип, место размещения - new
не нужно знать или заботиться о типе выражения p
.
После того, как обе p->~Const()
или memset (p, 0, sizeof *p)
ясно, что p
не указывает на действительный объект, так что p
может быть использован только в качестве указателя на хранение (void*
или char*
), например, чтобы реконструировать другой объект. В этот момент p->get0()
не допускается.
Большинства это верно, если под «p
может быть использован только» вы имеете в виду значения p
в то время, а не сам указателе (который может быть, конечно, также может быть назначено). И вы пытаетесь быть слишком умны с предметом - p
остается Const*
, даже если он используется только при размещении нового, которое не заботится о типе указателя.
«Я хочу восстановить стоимость p
в качестве Const*
».
Значение p
не было изменено после его первоначальной инициализации. Размещение - new
использует значение - оно не изменяет его. Нет ничего, чтобы восстановиться, поскольку ничего не потеряно. Тем не менее, dyp подчеркивает необходимость не использовать p
для управления объектом, поэтому, в то время как значение не было потеряно, оно не может использоваться напрямую по желанию.
«memcpy» должен быть эквивалентен простому назначению указателя 'q = p', не так ли? –
@ DanielJour Я так не думаю. 'p' больше не является верным указателем на объект типа' Const'. – curiousguy
Почему? Он указывает на правильно выровненную область памяти, в которой был создан объект правильного типа. (Кстати, вы, вероятно, должны добавить некоторые операции удаления) –