13

Похоже, что существует некоторая договоренность о том, что вы не можете называть willy nilly (int *) в массив char из-за правил псевдонимов C++.Является ли размещение новым юридически необходимым для помещения int в массив символов?

Из этого другого вопроса - Generic char[] based storage and avoiding strict-aliasing related UB - кажется, что разрешено (повторно) использовать хранилище путем размещения нового.

alignas(int) char buf[sizeof(int)]; 

void f() { 
    // turn the memory into an int: (??) from the POV of the abstract machine! 
    ::new (buf) int; // is this strictly required? (aside: it's obviously a no-op) 

    // access storage: 
    *((int*)buf) = 42; // for this discussion, just assume the cast itself yields the correct pointer value 
} 

Таким образом, это выше правовой C++ и является размещение нового на самом деле необходимо, чтобы сделать это законно?

+0

Связанный: http://stackoverflow.com/questions/38862092/is-it-legal-to-alias-a-char-array-through-a-pointer-to-int –

+0

https://godbolt.org/g/k2nVI9 –

+0

Очень актуальный, потенциальный обман: https://stackoverflow.com/questions/40873520/reinterpret-cast-creating-a-trivially-default-constructible-object –

ответ

12

Да, требуется размещение new, иначе вы нарушите строгий псевдоним (назначение access).

Является ли выше законным? Почти (хотя он будет работать практически во всех реализациях). Указатель, созданный вами при трансляции, не указывает на объект, потому что массив (теперь уничтожен) и объект int не являются pointer-interconvertible; используйте std::launder((int*)buf), или еще лучше, используйте возвращаемое значение размещения new.

+1

Строгое сглаживание не нарушается 'reinterpret_cast (buf) = 42', потому что он обращается к новому объекту' int' как lvalue типа 'int'. Взаимное преобразование указателя применимо при преобразовании одного «живого» указателя в другой, а не при преобразовании «мертвого» указателя в не-объект в живое. Изменить: я не уверен, что там нужен «отмывание»; правила все еще были в движении, которые я знал. – Potatoswatter

+1

@Potatoswatter Какой новый объект int? Я говорил о случае, когда ранее не было нового места для создания любого такого объекта. И я читаю указатель-интерконвертируемость, применимый в целом при указателях переинтерпретации. Независимо от того, что указатель, созданный оператором op с использованием приведения, не указывает на новый объект, как определено P0137, поэтому необходимо «отмываться». – Columbo

+0

[basic.lval] запрещает доступ к объекту, за исключением lvalues ​​определенных типов. В нем не рассматривается вопрос о том, существует ли еще объект. [basic.life]/6 в C++ 14 позволяет присваивать через 'reinterpret_cast' начало жизни; это удаляется P0137, поэтому C++ 17 (скорее всего) сделает размещение новым требованием. Вы правы в отношении конвертируемости указателя; P0137 соединяет его с 'reinterpret_cast' через' static_cast' из 'void *'. Поэтому «отмывание» необходимо для доступа к живому объекту (но не «отмыванию» хранилища для не-объекта). – Potatoswatter

-3
*((int*)buf) = 42; 

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