Rafał Wilk
Boost::value_initialized<T> zapewnia generyczny sposób inicjacji deklarowanych zmiennych, klas, wskaźników i innych typów. Korzystanie z value_initialized zapewnia zinicjowanie zdeklarowanego typu wartością domyślną w momencie deklaracji.
Zadeklarować zmienną można na wiele różnych sposobów, ale nie zawsze wartość zadeklarowanej zmiennej jest oczywista.
Przykładowo:
T zmienna;
Powyższa deklaracja nie determinuje wartości zadeklarowanej zmiennej,(często w zależności od systemu operacyjnego) zmienna ta może zostać zainicjowana wartością domyślną lub też pozostawiona z wartością bliżej nie określoną.
Można próbować na inne sposoby:
T zmienna = 0; T klasa = T();
W tym wypadku pierwszy przykład poprawnie zainicjuje zmienną lecz nie poradzi sobie z inicjacją klasy. Drugi przykład nie może być stosowany dla klas, które dziedziczą po boost::noncopyable lub mają prywatny lub niezdefiniowany konstruktor kopiujący.
W tych wszystkich przypadkach swoje zastosowanie znajduje value_initialized:
value_initialized<T> zmienna;
Zapewnia inicjację wartością domyślną, 0 dla zmiennych artymetycznych, null'em dla wskaźników, wartością false dla typu bool, wykorzystuje domyślny konstruktor klasy itd..
Oto jak wygląda klasa value_initialized:
template<class T> class value_initialized { public : value_initialized() : x() {} operator T&() const { return x ; } T& data() const { return x ; } private : unspecified x ; }
Udostepnia ona dwie możliwości dostępu do referencji do przechowywanego obiektu: operator T&() oraz metodę T& data().
Dodatkowo zdefiniowane została funkcja T& get( value_initialized<T> &x ), która także pozwala na dostęp do referencji obiektu.
template<class T> T const& get ( value_initialized<T> const& x ) { return x.data() ; } template<class T> T& get ( value_initialized<T>& x ) { return x.data() ; }
Co daje łącznie trzy możliwości otzrymania referencji do obiektu i wykorzystania jej:
void fun(&T); value_initialized<T> zmienna; fun(zmienna); fun(zmienna.data()); fun(get(zmienna));
Ze względu na dwie wersje funkcji get, dla wartości zmiennych i const, zaleca się właśnie ten sposób dostępu do referencji. Zapewniona zostaje kontrola dostępu i dlatego też:
value_initialized<int> zmienna ; get(zmienna) = 1 ; // poprawne value_initialized<int const> const_zmienna ; get(const_zmienna) = 1 ; // błąd: obiekt typu const value_initialized<int> const zmienna_const ; get(zmienna_const) = 1 ; // błąd: obiekt typu const value_initialized<int const> const const_zmienna_const ; get(const_zmienna_const) = 1 ; // błąd: obiekt typu const
value_initialized znajdzie wiele możliwości by ułatwić życie programiście, nie jest natomiast narzędziem, bez k†órego nie można żyć.
Przydatnym może okazać się inicjacja w miejscu deklaracji:
1. klas dziedziczących po boost::noncopyable lub z prywatnym konstruktorem kopiującym,
2. zmiennych arytmetycznych wartością zero,
3. wskaźników wartością null,
4. i pewnie wiele innych w zależności od potrzeb.