C++ Academy · Урок

Объединения и связанные с ними риски

Разделяйте память между типами

Урок 2 из 413 шагов

«Объединения и связанные с ними риски» — бесплатный урок C++ Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Что такое объединение

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

#include <iostream>
union Number {
    int i;
    float f;
};
int main() {
    Number n;
    n.i = 42;
    std::cout << n.i << "\n";
}

Размер объединения

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

#include <iostream>
union Mix { char c; int i; double d; };
int main() {
    std::cout << sizeof(Mix) << "\n"; // size of double (often 8)
}

Запись одного, чтение другого

Запись одного члена и чтение другого — это основной риск. Биты интерпретируются заново, что обычно приводит к неопределённому или неожиданному результату.

#include <iostream>
union Bits { int i; float f; };
int main() {
    Bits b;
    b.f = 1.0f;
    std::cout << b.i << "\n"; // reads float bits as int
}

Только один активный член

Безопасно читать можно только тот член, в который Вы записали значение последним. Отслеживайте активный член самостоятельно: объединение этого не запоминает.

#include <iostream>
union Value { int i; double d; };
int main() {
    Value v;
    v.d = 3.14;        // d is active
    std::cout << v.d << "\n";
}

Шаблон Tagged-объединения

Чтобы безопасно использовать объединения, сопоставляйте их с меткой (перечислением), которая хранит информацию об активном члене. Это предшественник std::variant, реализованный вручную.

#include <iostream>
struct Tagged {
    enum { Int, Double } tag;
    union { int i; double d; };
};
int main() {
    Tagged t; t.tag = Tagged::Int; t.i = 7;
    if (t.tag == Tagged::Int) std::cout << t.i << "\n";
}

Чтение правильного члена

Перед чтением всегда проверяйте метку. Чтение неправильного члена приводит к мусорным значениям.

#include <iostream>
struct Tagged {
    enum { Int, Double } tag;
    union { int i; double d; };
};
void print(const Tagged& t) {
    if (t.tag == Tagged::Int) std::cout << "int " << t.i << "\n";
    else std::cout << "double " << t.d << "\n";
}
int main() { Tagged t{Tagged::Double}; t.d = 2.5; print(t); }

Нетипичные члены

Размещение в объединении члена с конструктором или деструктором, например std::string, требует ручного конструирования и уничтожения. Это чревато ошибками и служит ещё одной причиной предпочесть std::variant.

Анонимные объединения

Анонимное объединение не имеет имени: доступ к его членам осуществляется напрямую. Это удобно внутри структуры, но правило активного члена всё равно действует.

#include <iostream>
struct Packet {
    int kind;
    union { int code; char letter; };
};
int main() {
    Packet p; p.kind = 1; p.code = 99;
    std::cout << p.code << "\n";
}

Почему объединения рискованны

Кратко об опасностях:

  • Нет информации о том, какой член активен.
  • Чтение неактивного члена приводит к неопределённому поведению.
  • Для нетривиальных типов требуется ручное управление временем жизни.

Когда объединения всё ещё полезны

Объединения по-прежнему полезны в низкоуровневом коде: для переинтерпретации байтов, экономии памяти в условиях ограничений встроенных систем или соответствия фиксированному двоичному формату. Для обычных данных «один из нескольких типов» предпочитайте более безопасную альтернативу.

Переход к std::variant

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

Быстрая проверка

Проверьте, насколько хорошо Вы поняли объединения.

Итоги

Вы узнали об объединениях:

  • Все члены используют один блок памяти.
  • Для чтения допустим только член, в который записали значение последним.
  • Используйте метку (перечисление), чтобы отслеживать активный член.
  • В современном C++ для безопасности предпочитайте std::variant.
Можно начать бесплатно

Изучай C++ с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
51
Уроки
203

Часто задаваемые вопросы

Урок «Объединения и связанные с ними риски» бесплатный?

Да — полный текст урока «Объединения и связанные с ними риски» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Объединения и связанные с ними риски»?

Разделяйте память между типами Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Объединения и связанные с ними риски»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Перечисление scoped enum class
  2. Объединения и связанные с ними риски
  3. std::variant
  4. std::visit
← Назад к C++ Academy