bit_cast



Начиная с C++20 появилась шаблонная функция std::bit_cast в заголовочном файле <bit>. Она предоставляет возможность создавать побитовые копии объектов с другим типом:

#include <bit>



double src = 42.0;

uint64_t dst = std::bit_cast<uint64_t>(src);



В конкретном примере переменные dst и src имеют одинаковый размер 8 байт, поэтому их содержимое может быть интерпретировано по-разному, в зависимости от типа представления: беззнаковое целое или число с плавающей запятой.



Аналогичного результата можно добиться и с помощью union или reinterpret_cast. Однако, это нельзя было сделать в compile time! Функция std::bit_cast поддерживает constexpr выражения. Бонусом мы получаем достаточно лаконичное приведение и не нарушаем strict aliasing.



В отличие от альтернативных способов, шаблонная функция std::bit_cast дополнительно проверяет, что исходный и целевой типы имеют одинаковый размер и могут быть тривиально скопированы. Последнее означает, что память объекта может быть просто скопирована без дополнительных действий и это будет рабочей копией. Если это не так, то такие операции могут нарушать жизненный цикл нового объекта.



Продемонстрирую проблему на примере с std::string. Объекты данного типа, в общем случае, хранят строку где-то в другом месте, а сами выступают в роли умной оболочки (RAII). Клонирование такого объекта «в лоб» создает потенциально опасную ситуацию: два объекта будут ссылаться на один и тот же уникальный ресурс и пытаться управлять им. Например, они оба попытаются освободить ресурс. У первого объекта это получится, а у второго приведет к ошибке double free: живой пример. Отсюда и вытекает ограничение, что нельзя создавать побитовых клонов нетривиально копируемых объектов. Им необходимо обязательно вызвать конструктор копирования, который выделит собственный ресурс.



Бывает и так, что изначально некоторые типы были реализованы тривиальными, но затем (в ходе доработок) потеряли такое свойство. Встроенные проверки std::bit_cast тут же сообщат о некорректности работы с таким типом.



Нельзя назвать std::bit_cast оператором приведения, т.к. эта штука все таки не включена в семантику языка (в отличие от static_cast, reinterpret_cast и т.д.) и вынесена в пространство имен библиотеки STL. Однако её стоит упомянуть в текущем цикле статей.



Оставляйте реакции, считаете ли вы этот пост полезным для других! А мы, как и всегда, будем рады прочитать ваши комментарии и ответить вопросы 😉



#cppcore #cpp20