Сценарий, в котором лучше использовать объединение instread структуры - PullRequest
1 голос
/ 11 января 2012

Может ли кто-нибудь дать мне сценарий, в котором разумно использовать union вместо struct в какой-то проблеме?

Спасибо

Ответы [ 2 ]

4 голосов
/ 11 января 2012

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

Допустим, у меня есть два сообщения, которые имеют идентичные данные, за исключением двух частей данных, которые взаимно исключают друг друга и имеют близкий размер (32-битное целое и 4-байтовый массив). Я могу объединить их, и сообщения могут совместно использовать структуру данных без увеличения размера, который они не будут использовать.

Знайте о проблемах:

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

Наличие объединения для ссылки на одни и те же данные с определениями разных типов является неопределенным поведением. Итак:

  • Не используйте объединение для обмана системы типов.
  • Не используйте объединение для хранения указателя и доступа к ссылке.
  • Не используйте объединение для создания более дешевых типов типов.

Кроме того, не используйте объединение с данными, которые являются указателями, которые можно удалить из другой точки кода. Вероятно, у вас есть удаленный указатель в вашем объединении, и вы случайно обращаетесь к данным, используя другое определение.

И самое главное, если вы не поняли этот ответ. Не используйте штуцер.

0 голосов
/ 11 января 2012

Объединения могут быть способом получить фактическое двоичное представление структуры данных.

#include <iostream>
#include <iomanip>

union MyUnion {
    int integer;
    unsigned char bytes[sizeof(int)];
};

int main() {
    MyUnion foo;
    foo.integer = 42;
    std::cout << "My computer represents " << foo.integer << " as:";
    for (int i = 0; i < sizeof(foo.bytes); ++i) {
      std::cout << ' ' << std::hex << std::setw(2) << std::setfill('0')
                << static_cast<unsigned int>(foo.bytes[i]);
    }
    std::cout << std::endl;
    return 0;
}

Есть и другие способы сделать это в C ++, но использование объединения делает намерение довольно прозрачным.

Обратите внимание, что результаты могут отличаться в зависимости от платформы (от младшего к старшему до старшего) и, возможно, от компилятора (как он упаковывает и дополняет массивы и типы данных).В большинстве случаев вам не нужно делать подобные вещи.

Иногда вам приходится иметь дело с устаревшим двоичным форматом с несколькими различными интерпретациями.(«Если первый байт равен 3, то следующее значение является строкой ASCII с нулевым символом в конце не более 16 байтов, в противном случае следующий объект, выровненный по DWORD, является смещением в блоке ресурсов ...»).Если вы понимаете все проблемы, связанные с порядком байтов и упаковкой, объединение позволяет относительно легко отделить такую ​​структуру.

...