Код: Выделить всё
class string {
struct long_mode {
size_t size;
size_t capacity;
char* buffer;
};
struct short_mode {
uint8_t size;
char buffer[23];
};
union {
long_mode heap;
short_mode sso;
}u;
bool is_long() const {
const unsigned char *p = reinterpret_cast(&u);
return (p[0] & 0b10000000) != 0;
}
};
Первый бит внутри объединения предназначался для хранения флага, указывающего, в каком режиме мы находимся в данный момент (long_mode, т. е. с использованием динамической памяти, или short_mode, т. е. с использованием символьного буфера[]).
Я сделал это таким образом. Насколько я понимаю, чтение байта само по себе не является UB, судя по тому, что говорит cppreference:
Если тип T_ref похож на любой из следующих типов, объект динамического типа T_obj доступен по типу через lvalue (до C++11) glvalue (начиная с C++11) типа T_ref: char, unsigned char или std::byte (поскольку C++17): это позволяет проверять представление любого объекта в виде массива байтов. T_obj — это знаковый или беззнаковый тип, соответствующий T_obj.
В частности, часть:
char, unsigned char или std::byte (начиная с C++17): это позволяет проверять объектное представление любого объекта в виде массива байтов.
Это означает, что вы может рассматривать байтовое представление любого объекта как массив байтов, что я и делаю.
Правильно ли я считаю, что здесь нет UB?
Как еще это можно реализовать «более правильно»?
Подробнее здесь: https://stackoverflow.com/questions/798 ... ss-members
Мобильная версия