Нарушается ли в приведённом фрагменте кода правило strict aliasing (строгого алиасинга)?

Рассмотрим следующий пример: <br/> <pre><code class="cpp">static Ref&lt;T&gt; FromThis(T* data)
  • 19 июля 2026 г. 3:00
Ответы на вопрос 2
Невозможно однозначно ответить по единственной строке `static Ref<T> FromThis(T* data)` — нужно видеть, что именно вы делаете с `data` внутри функции и какие типы фактически читаются/пишутся. Пока — кратко о главном, чтобы вы могли сами проверить свой код.

Коротко о правиле strict aliasing
- В C++ чтение/запись объекта через lvalue выражение допустимо только если тип lvalue:
  - точно совпадает с динамическим/статическим типом объекта, или
  - является совместимым (layout‑compatible) типом (редко в C++), или
  - — для объектов класса — является базовым классом этого объекта (доступ к соответствующему субобъекту), или
  - это char/unsigned char/std::byte (доступ к байтам объекта), или
  - это синоним типа (typedef) или одинаковый cv‑вариант, и ещё ряд частных случаев (например, для совместимых стандартных layout типов).
- Доступ через несовместимый тип — UB: компилятор может оптимизировать исходя из предположения, что такие алиасы не происходят.

Когда нарушение происходит (типичные ненадёжные паттерны)
- Вы делаете reinterpret_cast<T2*>(ptr) и затем разыменовываете его, а реальный объект — другого, несовместимого типа T1.
- Вы храните/извлекаете объекты через общую память, не соблюдая правила для тривиальных типов (например, пишете один тип, потом читаете другой).
- Вы используете указатели на разные несвязанные классы как будто они указывают на одно и то же место и читаете через несовместимый тип.

Когда всё в порядке
- Функция просто принимает T* и создаёт Ref<T> (т.е. хранит/использует тот же T*): это нормально.
- Вы приводите T* к указателю на базовый класс при реальном объекте производного класса — доступ к базовому субобъекту допустим.
- Вы обращаетесь к объекту через char*/unsigned char*/std::byte* для байтового доступа — это явно разрешено.
- Для тривиальных типов можно безопасно копировать битово (memcpy), и это не нарушает правило.

Пример опасного кода
- Неправильно:
  - U* up = reinterpret_cast<U*>(data); *up = ...; // если объект по data — не U и типы несовместимы — UB.
- Правильно:
  - Если нужен побайтовый доступ — использовать reinterpret_cast<char*>(data) и читать/писать байты.
  - Если нужно преобразовать битовое представление тривиального типа в другой тривиальный — использовать std::memcpy или std::bit_cast (C++20).

Рекомендации
- Покажите полный код тела FromThis и то, какие типы в нём используются — тогда дам конкретный ответ.
- Если вы делаете пининги/типпаны: рассмотрите std::bit_cast / memcpy / char* / union (с осторожностью) или отключение -fstrict-aliasing в крайнем случае.
- Для C++17/C++20 обратите внимание на std::launder, если имеете дело с размещённым new и повторным использованием storage.

Если пришлёте полный фрагмент (тело функции, что такое Ref<T>, какие касты делаются), я проверю конкретно и скажу, где именно есть UB и как исправить.
не совсем strict aliasing, тут UB другого рода. reinterpret_cast и вычитание sizeof( <code>RefMemoryBlockBase</code> ) — уже нарушение арифметики указателей: результат выходит за границы подобъекта <code>Value</code> . Плюс класс с virtual деструктором не standard-layout, а стандарт разрешает компилятору переиспользовать tail padding базового класса под члены наследника, так что <code>Value</code> не обязан лежать ровно на sizeof(Base) байт. И это не гипотетика: на gcc 13 с atomic sizeof(Base)=16, а Value реально лежит на смещении 12. alignof-assert от этого не спасает.
Похожие вопросы