C++ Unions: доступ к неактивному элементу массива гарантированно не разделяет пространствоC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 C++ Unions: доступ к неактивному элементу массива гарантированно не разделяет пространство

Сообщение Anonymous »

Рассмотрим следующее объединение C++:

Код: Выделить всё

struct Mystruct
{
char     *p;   // sizeof(p) == 8, alignof(p) == 8
uint32_t  sz;  // sizeof(sz) == 4, alignof(sz) == 4
};                 // sizeof(MyStruct) == 16 (with padding),
// alignof(MyStruct) == 8

union U
{
MyStruct s;
char     buf[16];
};
Мой вопрос: могу ли я безопасно прочитать только элемент last из buf[], даже если buf[] не является последним записанным в (активный) член союз? Я считаю, что в зависимости от того, как объединения должны работать в любой реализации компилятора, этот элемент (buf[15]) никогда не может быть перезаписан при записи в MyStruct s. Верно ли это?
Основная цель – максимально эффективно использовать пространство и при этом работать надежно.
Что я делаю: это объединение является единственным элементом данных для строкового класса (мы назовем его MyString). Внутри этого строкового класса структура MyStruct (на самом деле называемая AllocInfo) при использовании содержит указатель и длину динамически выделяемого блока памяти для строки (char* и uint32_t соответственно), когда хранится строка длиной более 15 символов. buf[] используется для оптимизации коротких строк (SSO): строка сохраняется непосредственно в этом буфере, если она помещается (15 или менее символов). Последний элемент этого массива символов используется как флаг. Когда используется SSO, он устанавливается в 0, а также удваивается как завершающий нулевой символ строки, когда длина хранимой строки равна точно 15. Когда используется динамически выделяемая память, этот флаг устанавливается в 1. Когда мне нужно прочитать string Я всегда сначала читаю этот флаг, чтобы определить, как получить к нему доступ.
Ограничения: я ориентируюсь на C++11. В настоящее время я компилирую для AMD64 Linux, но стараюсь быть как можно более независимым от платформы, планируя в ближайшее время компиляцию для ARM64 Linux (фактический размер массива символов buf[] рассчитывается во время компиляции как гарантированно всегда будет как минимум на один байт больше структуры, а также будет соответствовать alignof(max_align_t) для платформы). Я связываюсь с никакими библиотеками. Это означает, что я не могу использовать ничего из библиотек Standard C или Standard C++, а также ничего из пространства имен std::.
  • Насколько я понимаю, я иногда прочитайте флаг в buf[15], когда последний записанный член объединения был структурой MyStruct, которая по определению является неопределенным поведением (для C++11). Я понимаю. Однако я также считаю, что поведение в этом конкретном случае должно быть детерминированным и делать то, что я хочу, из-за требований к союзам (члены союза делят пространство и начальный адрес). Прав ли я в этом предположении?
  • В подобных случаях, когда элементы массива в объединении, к которым осуществляется индивидуальный доступ, сами не делят пространство ни с одним другим членом объединения (поскольку начальный адрес элемент находится за последним адресом, использованным любым другим членом союза) действительно ли это должно быть UB в C++?
  • Насколько я могу убедиться, код соответствует работает отлично и без проблем как в GCC, так и в Clang. При компиляции с каждым флагом предупреждения и уровнем строгости, который я могу вспомнить, на самом высоком уровне оптимизации диагностика не выводится, и код работает как положено. Однако компиляторы не обязаны выдавать диагностику для UB, поэтому я не могу ничего сделать из этого, верно?
  • Я мог бы, конечно, вытащить флаг из объединения и поставить это в другом месте класса строк. Но это будет означать, что я больше не смогу использовать 100% размера экземпляра строки для единого входа, что в некоторых случаях сделает его немного медленнее и немного менее эффективно использует пространство, что меня огорчает. Это также может означать увеличение sizeof(MyString) (в настоящее время 16) или снижение эффективности использования пространства в памяти самим строковым классом, когда многие экземпляры распределяются динамически.
Есть ли способ сделать то, что я делаю, не используя UB, при этом позволяя экземплярам класса экономить пространство?
Поскольку кажется, что все работает как есть, мне следует просто остановиться слишком много думаешь?

Подробнее здесь: https://stackoverflow.com/questions/784 ... hare-space
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»