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
- Zakresowa enum class
- Unie i związane z nimi ryzyko
- std::variant
- std::visit