97. Не используйте объединения для преобразований

We use cookies. Read the Privacy and Cookie Policy

97. Не используйте объединения для преобразований

Резюме

Хитрость все равно остается ложью: объединения можно использовать для получения "преобразования типа без преобразования", записывая информацию в один член и считывая из другого. Однако это еще более опасно и менее предсказуемо, чем применение reinterpret_cast (см. рекомендацию 92).

Обсуждение

Не считывайте данные из поля объединения, если последняя запись была не в это же поле. Чтение из поля, отличного от поля, в которое производилась запись, имеет неопределенное поведение, и использование этого метода еще хуже, чем применение reinterpret_cast (см. рекомендацию 92); в последнем случае компилятор, как минимум, может предупредить программиста и не допустить "невозможной интерпретации" наподобие указателя в char. При использовании для этой цели объединения никакая интерпретация не приведет к ошибке времени компиляции (как и к надежному результату).

Рассмотрим фрагмент кода, предназначенного для сохранения значения одного типа (char*) и выборки битов этого значения в виде величины иного типа (long):

union {

 long intValue_;

 char* pointerValue_;

};

pointerValue_ = somePointer;

long int gotcha = intValue_;

Здесь есть две проблемы.

• Данный код требует слишком многого. Он полагается на то, что sizeof(long) и sizeof(char*) равны и что их битовые представления идентичны. Эти утверждения справедливы не для всех возможных реализаций (см. рекомендацию 91).

• Он скрывает свое предназначение как от человека, так и от компилятора. Игры с объединениями затрудняют для компилятора поиск ошибок, связанных с типами, а для человека — выявление логических ошибок.

Исключения

Если две POD-структуры являются членами объединения и начинаются с полей одних и тех же типов, можно записывать одно из таких полей, а затем считывать данные из другого.

Ссылки

[Alexandrescu02b] • [Stroustrup00] §C.8.2 • [Sutter04] §36