Почему неконстантные ссылки на битовые поля запрещены?

Раздел 9.6 / 3 в C ++ 11 необычно ясен: «Неконстантная ссылка не должна быть привязана к битовому полю». Какова мотивация этого запрета?

Я понимаю, что невозможно напрямую привязать ссылку к битовому полю. Но если я скажу что-то вроде этого,

struct IPv4Header {
std::uint32_t version:4,         // assumes the IPv4 Wikipedia entry is correct
IHL:4,
DSCP:6,
ECN:2,
totalLength:16;
};

почему я не могу сказать это?

IPv4Header h;

auto& ecn = h.ECN;

Я ожидаю, что основной код на самом деле связать со всем std::uint32_t он содержит интересующие меня биты, и я ожидаю, что операции чтения и записи сгенерируют код для выполнения соответствующей маскировки. Результат может быть большим и медленным, но мне кажется, что он должен работать. Это будет соответствовать тому, как Стандарт говорит, что ссылки на const битовые поля работают (снова из 9.6 / 3):

Если инициализатор для справки
типа const T& является lvalue, который ссылается на битовое поле, ссылка привязана к временному
сохранить значение битового поля; ссылка не привязана к битовому полю напрямую.

Это говорит о том, что проблема заключается в записи в битовые поля, но я не вижу, что это такое. Я рассмотрел возможность того, что необходимое маскирование может привести к гонкам в многопоточном коде, но в 1.7 / 3 смежные битовые поля ненулевой ширины считаются одним объектом для целей многопоточности. В приведенном выше примере все битовые поля в IPv4Header объект будет рассматриваться как отдельный объект, поэтому многопоточный код, пытающийся изменить поле при чтении других полей, по определению уже будет неестественным.

Я явно что-то упускаю. Что это?

10

Решение

Неконстантные ссылки не могут быть привязаны к битовым полям по той же причине, по которой указатели не могут указывать на битовые поля.

Хотя не указано, занимают ли ссылки хранилище, ясно, что в нетривиальных случаях они реализуются как замаскированные указатели, и эта реализация ссылок «предназначена» авторами языка. Как и указатели, ссылки должны указывать на адресуемую единицу хранения. Невозможно привязать неконстантную ссылку к запоминающему устройству, которое не адресуется. Поскольку неконстантные ссылки требуют прямого связывания, неконстантные ссылки не могут быть связаны с битовым полем.

Единственный способ создать указатель / ссылку, которая может указывать на битовые поля, состоит в том, чтобы реализовать своего рода «суперпойнтер», который в дополнение к фактическому адресу в хранилище также будет содержать некоторую информацию о смещении в битах и ​​ширине в битах, чтобы сообщить коду написания, какие биты изменить. Обратите внимание, что эта дополнительная информация должна присутствовать во всех типах указателей данных, поскольку в C ++ нет такого типа, как «указатель / ссылка на битовое поле». Это в основном эквивалентно реализации модели адресации хранилища более высокого уровня, совершенно не связанной с моделью адресации, предоставляемой базовой операционной системой / аппаратной платформой. Язык C ++ никогда не собирался требовать такого рода абстракции от базовой платформы из соображений чистой эффективности.

Один жизнеспособный подход состоял бы в том, чтобы ввести отдельную категорию указателей / ссылок, таких как «указатель / ссылка на битовое поле», которая имела бы более сложную внутреннюю структуру, чем обычный указатель / ссылка данных. Такие типы могут быть преобразованы из обычных указателей / ссылочных типов данных, но не наоборот. Но, похоже, оно того не стоит.

В практических случаях, когда мне приходится иметь дело с данными, упакованными в биты и последовательности битов, я часто предпочитаю реализовывать битовые поля вручную и избегать битовых полей языкового уровня. Имя битового поля является объектом времени компиляции без возможности выбора во время выполнения любого вида. Когда выбор во время выполнения необходим, лучшим подходом является объявление обычного uint32_t поле данных и управлять отдельными битами и группами битов внутри него вручную. Выбор во время выполнения такого ручного «битового поля» легко осуществляется посредством масок и сдвигов (оба могут быть значениями во время выполнения). По сути, это близко к ручной реализации вышеупомянутых «суперпойнтеров».

8

Другие решения

Вы не можете взять неconst ссылка на битовое поле по той же причине, по которой вы не можете получить его адрес &: его фактический адрес не обязательно соответствует char, который определенно является наименьшей адресуемой единицей памяти в абстрактной машине C ++. Вы можете взять const ссылка на него, потому что компилятор может свободно копия значение, поскольку оно не будет видоизменено.

Рассмотрим вопрос об отдельной компиляции. Функция, принимающая const uint32_t& необходимо использовать тот же код для работы на любом const uint32_t&, Если для обычных значений и значений битовых полей требуется другое поведение записи, тип не кодирует достаточно информации, чтобы функция могла корректно работать с обоими.

10

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector