https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2590r2.pdf We further added a precondition missing in [P0593R5] stating that the passed-in storage is suitably aligned for the type of object being created.
Из объяснения я не понял, почему reinterpret_cast приведет к UB, а lifetime_as нет? Будто в С++20 поменялись какие-то базовые концепции, есть ли какой-то ёмкий обзор? Зачем компилятору знать, кто владеет объектом или кто его инициализировал, еcли тот well-aligned и POD?
Кстати, хороший вопрос, как правильно поступить в такой ситуации: Хочу писать и читать обычный wav файл, он состоит из заголовка и данных, заголовок представляется структурой, я заполнил поля структуры и записал в файл как массив байт через reinterpret_cast<std::byte* > ( ) Читаю так же. Вопрос - а как надо правильно в С++ ?
А тут все сложно, запутанно и просто одновременно. Имхо со времен введения понятия стрикт-алиасинга и оптимизации на этом деле компилятор слишком агрессивно начинает это дело оптимизировать (выкидывать код) из-за чего reinterpret_cast вроде как низя(не рекомендуется) и вводят bit_cast https://en.cppreference.com/w/cpp/numeric/bit_cast Также для защиты планеты в стандарте запрещают смешивание типа на unione - мол записал поле foo вот и юзай только его, а иначе UB. Даже если ты даешь гарантию, выравнивание и т.п... боль и страдание Да понятно что в стандарте имели ввиду что сложные типы(не тривиальные) с виртуальностью, атомиками и бла бла бла в union-е создал, а юзаешь поле которое не сном не духом про эту сложность, вывод, ты - идиот(ктож спорит), но под это дело попало и то что записав 4х байтный инт, байтами ты не можешь прочитать его как инт, читай блин байты! тот же Clang орет мол ай ай так делать низя. из-за чего проверить эндианс через union считается UB (хотели как лучше...) Вплоть до юзай bit_cast или сам memcpy пиши, мол компилятор поймет и оптимизирует это дело. будет быстро не переживай. то что ты для этого обмазался лишним кодом, ну UB же, сам виноват. Потом вводят lifetime_as который как раз и делает то что делали программисты на union-е. мол чувак, там лежат байты, я хочу чтоб ты без всякого UB и мега конструкторов и бла бла бла, просто понял что это вот эта штука(как и откуда эти байты не важно), доверься мне я знаю что я делаю. Поэтому в этом предложении и требуют чтоб там было все выровнено и лежало так как и должно! Я задал вопрос выше, а какое поле будет активным если мы скажем что вот эти байты вот это lifetime_as<same_union>? Полухин говорит, что вроде как любое! Тем самым lifetime_as вроде как легализует смешивание типа на unione. Возможно еще будут уточнения, но если это так, может и не нужен был lifetime_as, а надо было убрать из стандарта UB на чтение не активных полей union. Да требовать, что программист понимает что он делает, да он должен гарантировать выравнивание, паддинги, упаковку и все такое. Если программист не дал этих гарантий ну он в рантайме получит тыквы в виде HardFault или из-за выравнивания BusFault и т.п НО он это получит и из-за lifetime_as, да даже если сделает memcpy если сделает ее в не правильно выровненную память. PS. gcc ну по крайней мере собранный ARM-ом для baremetal игнорит UB для union что радует.
спасибо за такое полное разъяснение, картина становится понятнее =) Ты прям вот ответил про то, про что я спросил, как вышло и что делать =) В принципе, то, что теперь это UB, и даже может быть какой-нить санитайзер научится про это давать полезную информацию, выглядит из твоего объяснения хорошей штукой, поскольку понижает шанс выстрелить себе в ногу случайно. Но вот все базы кодов, в том числе современных, высоконагруженных и крутых проектов, в лучшем случае переползли на С++11\14, а некоторые еще не могут сделать и этого (например, если заявлена поддержка старых никсовых ядер, идущих с gcc 4.4). И все они довольно активно пользуются вещами, вроде reinterpret_cast, который раньше был ОК, а теперь UB. Т.е. огромные тонны кода, оказывается, непереводимы на более современные компиляторы, т.к. те потеряли обратную совместимость, как минимум вот этим вот новым правилом про UB, и я не удивлюсь, если чем-то еще тоже. Как предполагается действовать в этом случае? =)
да хз как действовать, если юзать для каждого чиха memcpy или bit_cast в надежде что все айс. ну наверное. и идея то понятна, сделать код быстрее. ведь у нас же типизированный язык. как указатель на char может поменять вот этот инт? ну по идее никак(стрикт алиасинг). но из-за низкоуровневых штук, смешиваниях типов на union-e получается можно. тут как раз и вводят мол давайте сделаем это UB и все... сделать то сделали. и пошли ситуации, даже не на бареметалл а тут в биг системе. ну буфер у тебя все айс. выровнил ты. структура у тебя упакованная. прилетела она тебя (байтами) через сетку. а по всем стандартам не можешь ты мацать ее. не можешь и все. лайфтайм же не начинался, тут на помощь и пришел этот lifetime_as, но из-за него я могу обойти UB для union-a? эмм тут палка о двух концах. либо lifetime_as для union-a запретят. либо скажут делать switch case на каждое поле для lifetime_as. ХЗ я сам не знаю. пока тупо юзаю в эмбедете для протокольных вещей тупо union да даю гарантию на то что буфер выровнен. если данные смешанные, структуры упаковываю (для них компилятор сам инты читает байтами, если видит, что начальное выравнивание не кратно 4 и т.п). Да приходиться лезть в асм код, смотреть а все ли айс. Так что да, ждем развития и пояснений на счет lifetime_as.
"Новым"? Это правило уже лет цать существует :) start_lifetime_as() - долгожданная "официальная" лазейка
Потому что компиляторы привыкли к тайп паннингу через юнионы, и не жрут его. Только кланг жрет и юнионы, но отключается через параметр -fstrict-aliasing
Есть: это UB было всегда
т.е. всегда reinterpret_cast участка памяти well-aligned в POD структуру — UB? Не знал, это очень частый и везде используемый паттерн же. Тогда вопрос: начиная с какого компилятора этот извечный UB стандарта становится проблемой для разработчика, т.к. раньше нигде это проблемой для разработчика не было. gcc 2.9.2 (о да, такое тоже иногда приходится поддерживать) — вроде бы нет gcc 4.1.2 — вроде бы нет gcc 4.4.7 — вроде бы нет gcc 4.8.2 — вроде бы нет gcc 8.0+ — ?
С C++20 - нет. См. [p0593r6].
P0593R6: Implicit creation of objects for low-level object manipulation (by Richard Smith, Ville Voutilainen) (2020-02-14) (Related: GitHub issue)
Обсуждают сегодня