) и обратно к исходному типу возвращает исходное значение указателя. - конец примечания]

ли (семантическая) разница между возвращаемым значением размещения new и приведенным значением его операнда?

struct Foo { ... };
char buffer[...];

Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);

Есть лиa а такжеb чем-то отличаются?

РЕДАКТИРОВАТЬ: Основываясь на комментарии DaBler, этот вопрос говорит о том, что есть разница, если используются члены const / reference:Размещение нового и назначение класса с постоянным членом

Итак, мой немного обновленный вопрос:a а такжеb отличаются в любом случае, еслиFoo не имеет постоянных или референтных членов?

 geza05 дек. 2017 г., 13:23
@ UKMonkey: извините, может быть, я не достаточно ясно. Обе линии запускаются, сначала новое размещение, а затем бросок.
 DaBler05 дек. 2017 г., 13:29
Да, есть разница, если класс содержит константные члены. Видетьэтот вопрос для деталей.
 UKMonkey05 дек. 2017 г., 13:21
новый (буферный) Foo; вызовет конструктор объекта; другой нет.

Ответы на вопрос(2)

a законно в то время какb не является. Из[Basic.compound]

Два объектаa а такжеb являются взаимозаменяемыми по указателю, если:

они один и тот же объект, или

один представляет собой объект объединения стандартной компоновки, а другой является нестатическим членом данных этого объекта, или

один - это объект класса стандартной компоновки, а другой - первый элемент не статических данных этого объекта или, если объект не имеет нестатических элементов данных, первый подобъект базового класса этого объекта ([class.mem] ), или же

существует объектc такой, чтоa а такжеc являются взаимозаменяемыми указателями, иc а такжеb являются указателями взаимозаменяемыми.

Если два объекта являются взаимозаменяемыми по указателю, то они имеют одинаковый адрес, и можно получить указатель на один из указателя на другой черезreinterpret_­cast, [Примечание: объект массива и его первый элемент не являются взаимозаменяемыми по указателю, даже если они имеют один и тот же адрес. - конец примечания]

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

Запись[Expr.reinterpret.cast] только гарантииreinterpret_cast<char*>(b) == buffer.

Указатель на объект может быть явно преобразован в указатель на объект другого типа. Когда prvaluevуказателя типа объекта преобразуется в указатель типа объекта «указатель наcv T», Результатstatic_­cast<cv T*>(static_­cast<cv void*>(v)), [Примечание: преобразование значения типа «указатель наT1На указатель типаT2" (гдеT1 а такжеT2 являются типами объектов и где требования выравниванияT2 не более строгие, чем те,T1) и обратно к исходному типу возвращает исходное значение указателя. - конец примечания]

Решение Вопроса

a можно безопасно использовать для прямого доступа кFoo объект, созданный путем размещенияновое выражение (который мы назовемx для удобства пользования). С помощьюb требуетstd::launder.

Значениеa указан в[Expr.new] / 1:

Если сущность не является объектом массива, результатомновое выражение указатель на созданный объект

Значениеa поэтому "указатель наxMsgstr "Этот указатель, конечно, можно безопасно использовать для доступаx.

reinterpret_cast<Foo*>(buffer) применяет преобразование массива в указательbuffer (видеть[Expr.reinterpret.cast] / 1). Результирующим значением после применения преобразования является «указатель на первый элементbuffer". Этоreinterpret_cast указателя объекта на указатель объекта другого типа, и определяется как эквивалентstatic_cast<Foo*>(static_cast<void*>(buffer)) по[Expr.reinterpret.cast] / 7.

Внутреннее приведение кvoid* на самом деле неявное преобразование. в[Conv.ptr] / 2,

Значение указателя не изменяется при этом преобразовании.

Поэтому внутренний бросок даетvoid* со значением "указатель на первый элементbuffer».

Внешний состав регулируется[Expr.static.cast] / 13, который я слегка переформатировал в пункты пули:

Значение типа «указатель наCV1 void»Можно преобразовать в значение типа« указатель наCV2 T", гдеT это тип объекта иCV2 является той же квалификацией cv или большей квалификацией, чемCV1.

Если исходное значение указателя представляет адресA байта в памяти иA не удовлетворяет требованию выравниванияT, тогда результирующее значение указателя не указано.

В противном случае, если исходное значение указателя указывает на объектaи есть объектb типаT (игнорируя cv-квалификацию), который является взаимозаменяемым с указателемaрезультат - указатель наb.

В противном случае значение указателя не изменяется при преобразовании.

При условии, чтоbuffer правильно выровнен (у вас будут проблемы задолго до этого момента, если это не так), первая пуля неприменима. Вторая пуля также неприменима, так как нетуказатель interconvertiblity Вот. Отсюда следует, что мы попали в третий пункт - «значение указателя не изменяется при преобразовании» и остается «указатель на первый элементbuffer».

Таким образом,b не указывает наFoo объектx; вместо этого он указывает на первыйchar элементbufferхотя его типFoo*, Поэтому он не может быть использован для доступаx; попытка сделать это приводит к неопределенному поведению (для случая нестатического члена данных, пропуская из[Expr.ref]; для случая нестатической функции-члена[Class.mfct.non-статические] / 2).

Чтобы восстановить указатель наx изb, std::launder может быть использован:

b = std::launder(b); // value of b is now "pointer to x"
                     // and can be used to access x

Ваш ответ на вопрос