union în C++

Un tip în care toți membrii împart aceeași zonă de memorie; la un moment dat doar unul dintre ei are o valoare validă.

Sintaxă
union Nume {
    int intreg;
    double real;
};

Ce face union

Într-o struct, fiecare membru are locul lui. Într-un union, toți membrii stau în același loc, deci mărimea lui este cea a celui mai mare membru. Poți ține fie un int, fie un double, dar nu pe amândouă deodată.

Membrul scris ultima dată este membrul „activ”. Doar pe el ai voie să-l citești; tu trebuie să ții minte care este (de obicei cu o variabilă separată de tip enum, numită etichetă).

În C++ modern, std::variant face același lucru în mod sigur: ține minte singur ce tip conține și aruncă excepție dacă citești tipul greșit. union rămâne util în cod de nivel jos și în legătura cu biblioteci C.

Exemple

Exemplul 1: Membrii împart memoria

#include <print>

union Valoare {
    int intreg;
    double real;
};

int main() {
    Valoare v;
    v.intreg = 42;
    std::println("Întreg: {}", v.intreg);
    v.real = 3.5;  // acum membrul activ este real
    std::println("Real: {}", v.real);
    std::println("sizeof(Valoare) = {}", sizeof(Valoare));
}

Rezultat

Întreg: 42
Real: 3.5
sizeof(Valoare) = 8

Exemplul 2: Union cu etichetă

Câmpul tip ține minte ce membru este activ, așa că afișarea citește întotdeauna membrul corect. Uniunea fără nume din interior face ca membrii să se scrie direct (m.bucati).

#include <print>

struct Masura {
    enum class Tip { bucati, kilograme } tip;
    union {
        int bucati;
        double kilograme;
    };
};

void afiseaza(const Masura& m) {
    if (m.tip == Masura::Tip::bucati) {
        std::println("{} bucăți", m.bucati);
    } else {
        std::println("{} kg", m.kilograme);
    }
}

int main() {
    Masura oua{Masura::Tip::bucati, {}};
    oua.bucati = 30;
    Masura mere{Masura::Tip::kilograme, {}};
    mere.kilograme = 2.5;
    afiseaza(oua);
    afiseaza(mere);
}

Rezultat

30 bucăți
2.5 kg

Greșeli frecvente

  • Scrii un membru și citești altul (v.real = 3.5; v.intreg) ca să „vezi biții”. În C++ este comportament nedefinit; pentru asta există std::bit_cast (C++20).
  • Pui în union membri cu constructori și destructori (std::string) fără să gestionezi manual construirea și distrugerea lor. Folosește std::variant.

Comenzi înrudite

  • struct: Grupează mai multe valori într-un singur tip; ca o clasă, dar cu membri publici implicit.
  • enum: Definește un tip cu o listă fixă de valori cu nume, de exemplu zilele săptămânii sau stările unei comenzi.
  • sizeof: Dă numărul de octeți ocupați în memorie de un tip sau de o variabilă; se calculează la compilare.
  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.
  • std::variant: O valoare care are, la un moment dat, exact unul dintre mai multe tipuri posibile (union sigur).
  • std::bit_cast: Reinterpretează biții unui obiect ca alt tip de aceeași mărime, în mod sigur (de exemplu biții unui float ca uint32_t).