Posts tagged ‘aggregates’

Domyślna inicjalizacja zmiennych

2010-03-17 1:57

Używanie zmiennych bez uprzedniego nadania im wartości to stosunkowo częsty błąd. Wiele języków kompilowanych będzie z tego powodu stroiło fochy wahające się od ostrzeżeń podczas kompilacji przez błędy tejże aż po wyjątki w czasie wykonania programu (przynajmniej w wersji debugowej). To zresztą bardzo dobrze, gdyż alternatywą jest korzystanie ze zmiennej, której zawartością są jakieś losowe śmieci w pamięci.

Tak więc zmienne trzeba inicjalizować i w niemal każdym języku da się to zrobić mniej więcej tak:

  1. int x = 5;

W C++ oczywiście też. Jednak w C++ mamy też feature, który nazywa się inicjalizacją domyślną. Opiera się on założeniu, że dany typ (tj. obiekt tego typu) może się sam zainicjalizować bez żadnych dodatkowych informacji – czyli że np. ma rozsądną wartość domyślną albo bezparametrowy konstruktor. Stąd T() będzie “domyślnym obiektem typu T“, który możemy łatwo uzyskać, nie mając w ogóle pojęcia, czym ów typ T w istocie jest (codzienność szablonów, swoją drogą).
Inicjalizacja zmiennej tego typu domyślną wartością będzie więc wyglądała mniej więcej tak:

  1. T foo = T();

Co bardziej spostrzegawczy zauważą jednak, że mamy tutaj dwie operacje: konstrukcję obiektu i kopiowanie go. Nie radzę jednak próby “optymalizacji” w postaci zamiany na deklarację T foo(); – można się nielicho zaskoczyć. Najlepiej pozostawić to zadanie kompilatorowi; przynajmniej w teorii powinien on sobie z nim bez problemu poradzić.

W powyższy sposób możemy domyślnie inicjalizować dowolne typy zmiennych. Dla pewnej ich podgrupy – zwanej agregatami – możemy jednak zastosować inne rozwiązanie. Cóż to jednak są te agregaty? Otóż są to typy złożone (tablice, struktury, itp.), które nie posiadają zdefiniowanych przez programistę konstruktorów. Mimo że instrukcja T() działa zupełnie dobrze również dla nich, dopuszczalne jest stosowanie nieco innej formy inicjalizacji.
Formą ta jest lista inicjalizacyjna. Można ją niekiedy spotkać w kodzie korzystającym z jakiegoś API, które operuje na dużych strukturach:

  1. WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; // {...} to inicjalizator
  2. wc.lpszClassName = TEXT("MyVeryOwnAndCuteWindow");
  3. wc.hInstance = hInstance;
  4. // itd.

Chodzi tu po prostu o podanie wartości dla kolejnych elementów agregatu, czyli pól w strukturze/klasie lub komórek tablicy; całą tę listę zamykamy w nawiasy klamrowe. Nie musi ona być przy tym pełna: jeśli jakieś pozycje zostaną pominięte, to odpowiadające im pola/komórki zostaną automatycznie zainicjalizowane w sposób domyślny. W przykładzie powyżej inicjalizujemy więc strukturę tak, że pierwsze pole zawiera jej rozmiar, a reszta domyślne wartości (czyli pewnie zera).
Dane dla pierwszego pola zostały wprawdzie tutaj podane jawnie, jednak w ogólności nie jest to wymogiem. Na liście inicjalizacyjnej możemy równie dobrze opuścić wszystkie pozycje i to właśnie jest ten drugi, uniwersalny sposób inicjalizacji agregatu. Wygląda on więc po prostu tak:

  1. D3DVECTOR v = {};

Jakkolwiek nietypowo (jak na kod C++) linijka ta wygląda, jest ona najzupełniej poprawna. W wyniku jej wykonania nowo zadeklarowany wektor v będzie miał wszystkie współrzędne wyzerowane.

Tags: , ,
Author: Xion, posted under Programming » 10 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.