0Pricing
C++ Academy · Lekcja

Unie i związane z nimi ryzyko

Współdziel pamięć między typami

Unie i związane z nimi ryzyko to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.

Czym jest unia?

union pozwala kilku składowym współdzielić ten sam obszar pamięci. W danym momencie prawidłowa jest tylko jedna składowa, a unia ma rozmiar nie większy niż jej największa składowa.

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

Rozmiar unii

Ponieważ składowe nakładają się na siebie, sizeof unii jest równy rozmiarowi jej największej składowej (powiększonemu o ewentualne dopełnienie wyrównujące), a nie sumie rozmiarów.

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

Zapisywanie jednej, odczytywanie innej

Zapisywanie jednej składowej i odczytywanie innej to główne ryzyko. Bity są interpretowane na nowo, co zwykle prowadzi do niezdefiniowanego lub zaskakującego działania.

#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
}

Tylko jedna aktywna składowa

Jedyną składową, którą można bezpiecznie odczytać, jest ta, do której ostatnio wykonano zapis. Należy samodzielnie śledzić, która składowa jest „aktywna” — unia tego nie zapamiętuje.

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

Wzorzec unii ze znacznikiem

Aby bezpiecznie używać unii, należy połączyć ją ze znacznikiem (typem wyliczeniowym), który przechowuje informację o aktywnej składowej. Jest to ręcznie implementowany przodek 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";
}

Odczytywanie właściwej składowej

Przed odczytem zawsze należy sprawdzić znacznik. Odczyt niewłaściwej składowej daje bezwartościowe dane.

#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); }

Nietrywialne składowe

Umieszczenie w unii składowej mającej konstruktor lub destruktor (takiej jak std::string) wymaga ręcznego konstruowania i niszczenia obiektu. Jest to podatne na błędy i stanowi kolejny powód, by preferować std::variant.

Unie anonimowe

Unia anonimowa nie ma nazwy, a do jej składowych uzyskuje się dostęp bezpośrednio. Jest przydatna wewnątrz struktury, ale nadal obowiązuje ta sama zasada dotycząca aktywnej składowej.

#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";
}

Dlaczego unie są ryzykowne

Podsumowanie zagrożeń:

  • Unia nie pamięta, która składowa jest aktywna.
  • Odczyt nieaktywnej składowej powoduje niezdefiniowane zachowanie.
  • Typy nietrywialne wymagają ręcznego zarządzania czasem życia.

Kiedy unie nadal są przydatne

Unie nadal są przydatne w programowaniu niskopoziomowym: do reinterpretowania bajtów, oszczędzania pamięci w ograniczonym kodzie systemów wbudowanych lub odwzorowywania ustalonego układu binarnego. W przypadku codziennych danych reprezentujących „jeden z kilku typów” należy preferować bezpieczniejszą alternatywę.

W kierunku std::variant

std::variant to bezpieczna typowo unia, która śledzi za Ciebie aktywny typ i zgłasza wyjątek przy próbie uzyskania dostępu do niewłaściwego typu. W dalszej części kursu poznasz ten typ dokładniej.

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat unii.

Podsumowanie

Poznałeś/Poznałaś unie:

  • Wszystkie składowe współdzielą jeden blok pamięci.
  • Odczytywać można tylko składową, do której ostatnio wykonano zapis.
  • Do śledzenia aktywnej składowej należy używać znacznika (typu wyliczeniowego).
  • We współczesnym C++ dla bezpieczeństwa należy preferować std::variant.

Często zadawane pytania

Czy lekcja „Unie i związane z nimi ryzyko” jest bezpłatna?

Tak — pełny tekst „Unie i związane z nimi ryzyko” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Unie i związane z nimi ryzyko”?

Współdziel pamięć między typami Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C++ Academy?

Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Unie i związane z nimi ryzyko”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?

Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Zakresowa enum class
  2. Unie i związane z nimi ryzyko
  3. std::variant
  4. std::visit
← Powrót do C++ Academy