= {1, 1, 1, 1, 0, 0, 0, 0};
uint32_t *p = reinterpret_cast<uint32_t *>(buffer);
printf("0x%x\n", *p);
Зависит от того какой настоящий тип у uint8_t. Если один из стандартной тройки char, unsigned char, byte, вроде все ок.
В Си char, signed char и unsigned char не compatible
Да, здесь прямое нарушение, как минимум дважды
Но не правил алиасинга.
Нет, и правил алиасинга, именно что можно алиасить чаром всё что угодно, но не в обратную сторону. Здесь можно было бы поправить через использование memcpy, однако мы должны были бы копировать часть буфера, по размеру равную uint32_t
Возможно я ошибаюсь, но буфер char'ов всегда можно было использовать под любой тип. Да, объект в этом буфере нужно в начале создать и в примере выше есть проблемы с лайфтамом. Но мне сложно поверить что там есть проблема с алиасингом.
тривиальные типы и структуры вроде можно рентерпреткастить в/из char. Но не помню наверняка
Вопрос можно поставить даже проще: как реализовать std::vector если нельзя скастить массив char в массив T?
Скастить-то можно, но не так https://eel.is/c++draft/basic.lval#11
Так это проблема с лайфтамом, а не алиасингом.
Нет, здесь попытка прочитать значение через несоответствующий тип, нарушение strict aliasing. Чётко по пункту стандарта
Окей, я сформулирую свою мысль по-другому. В этом примере нет UB: char* buf = new char[sizeof(T)]; // assuming here that T has no overalignment new(buf) T; T* p = reinterpret_cast<T*>(buf); // я специально разделил placement new и каст *p; // read or write T
В первой части, до каста, нет
Почему после каста UB появляется? После placement new по адресу buf уже есть объект с типом T.
Хотя я не прав и адрес возвращенный placement new может отличаться от reinterpret'а из-за особенностей new. Но это опять же не проблема алиасинга. upd: Это касается только создания массивов. Так как placement new у меня создает объект, а не массив, здесь проблемы не должно быть.
Здесь нет UB, потому что есть динамический тип и с указателем на него ты работаешь, в исходном примере динамического типа нет.
Да, пожалуй здесь я ошибся
Да, но изначальный вопрос был только о алиасинге, а не UB в целом.
Нет UB из-за strict aliasing violation потому, что динамические типы совпадают* А там есть
Ладно, предлагаю постановить что там есть UB по многим причинам: 1. aliasing 2. lifetime 3. alignment (возможно я еще что-то забыл) Я бы сказал, что нарушение lifetime было первично и если исправить его (как в моем примере) проблемы с алиасингом не будет. Но видимо это зависит от точки зрения.
Согласен. Впрочем, используя type punning мы могли бы обойти нарушение strict aliasing и без решения каких-либо проблем с lifetime. Точнее, у нас бы их попросту не было
Это ведь про нововведение 20го стандарта? Там был список функций, которые такое делают: malloc, memcpy и прочие, но я не уверен, что оно неявно создает типы в обычных массивах на стеке. Пойду поищу пропозал.
Вообще, в C++20 добавился bit_cast, насчёт memcpy, как мне кажется, это было и до 20-го стандарта
> We propose that at minimum the following operations be specified as implicitly creating objects: > * Creation of an array of char, unsigned char, or std::byte implicitly creates objects within that array. Таки должно работать с обычными массивами. Если что это из [P0593R6].
P0593R0: What to do with buffers that are not arrays, and undefined behavior thereof? (by Ville Voutilainen) (2017-02-05) (Related: GitHub issue) P0593R1: Implicit creation of objects for low-level object manipulation (by Richard Smith, Ville Voutilainen) (2017-10-16) (Related: GitHub issue) P0593R2: Implicit creation of objects for low-level object manipulation (by Richard Smith) (2018-02-11) (Related: GitHub issue) P0593R3: Implicit creation of objects for low-level object manipulation (by Richard Smith) (2019-01-18) (Related: GitHub issue) P0593R4: Implicit creation of objects for low-level object manipulation (by Richard Smith) (2019-06-17) (Related: GitHub issue) P0593R5: Implicit creation of objects for low-level object manipulation (by Richard Smith) (2019-10-07) (Related: GitHub issue) P0593R6: Implicit creation of objects for low-level object manipulation (by Richard Smith, Ville Voutilainen) (2020-02-14) (Related: GitHub issue)
Не думаю. С memcpy трюк заключался в том, чтобы скопировать данные в уже существующий объект нужного типа. По-моему на cppref в статье про bit_cast была реализация для старых стандартов использующая этот прием.
Ну да, объект должен был уже существовать. Вероятно, в том примере в любом случае необходимо было решить проблему с lifetime, так или иначе
кажется в с++20 это и поправили
кстати можно же делать void* ptr = operator new(16, std::align_val_t(16));
Мне лень было искать точный синтаксис, чтобы задать правильное выравнивание, поэтому я использовал то что new char[] имеет максимальное "обычное" выравнивание и добавил комментарий про overalignment. =)
разве через new если ааллцировать то у чар будет макс выравнивание? Я думал только через malloc
в стандарте оно вот здесь
Обсуждают сегодня