Intelignetne wskaźniki w C++11 – część 1

Każdy, kto choć pobieżnie zetknął się z językiem C lub C++ musiał mieć styczność także z elementem tych języków programowania, jakim są wskaźniki (ang. pointers). Te specjalne zmienne służą do przechowywania adresów innych zmiennych. Jest to bardzo przydatny element języka. Jednak w pewnych sytuacjach wskaźniki mogą być jednak niebezpieczne. Dobrze to widać w przypadku zarządzania cyklem życia obiektów, ponieważ programista musi zadbać o to, aby obiekt istniał co najmniej tak długo jak wskaźnik, który się do niego odnosi. Stopień trudności jest większy, jeżeli do jednego obiektu odnosi się wiele wskaźników. Po zakończeniu cyklu życia wskaźnika (lub wskaźników) należy zadbać o to, aby zniszczyć obiekt. Jest to konieczne, ponieważ zapobiega wyciekom pamięci (ang. memory leaks). W tych wszystkich działaniach programistę wspomagają tzw. inteligentne wskaźniki. Różnią się one od zwyklych wskaźników tym, że przechowują nie tylko adres obiektu, lecz ponadto informację o jego właścicielu.

Standard C++98 wprowadził klasę auto_ptr, która obsługiwała tzw inteligentne wskaźniki (smart pointers). W standardzie C++11 wprowadzono trzy nowe klasy inteligentnych wskaźników:

a) unique_ptr – klasa przechowująca inteligentny wskaźnik z własnością na wyłączność, zastąpiła ona klasę auto_ptr ze standardu C++98 której używanie nie jest obecnie polecane (deprecated),

b) shared_ptr – klasa przechowująca inteligentny wskaźnik z własnością współdzieloną,

c) weak_ptr – klasa przechowująca inteligentny wskaźnik do przerywania pętli w strukturach danych, które są współdzielone.

Klasa unique_ptr

Dodana w standardzie C++11 klasa unique_ptr udostępnia interfejs wskaźnika odnoszącego się do obiektów posiadanych na wyłączność przez jednego użytkownika. Podobnie jak pozostałe klasy inteligentnych wskaźników definiuje obiekty przy pomocy instrukcji new. Gdy nadchodzi potrzeba usunięcia unique_ptr wywoływana jest automatycznie metoda delete, która zwalnia pamieć i nie dopuszcza do wystąpienia jej wycieków. Na tym polega „intelignecja” wskaźnika. W wydatny sposób jest tu uproszczona praca programisty, który nie musi pamiętać o użyciu instrukcji delete.

Aby użyć inteligentnego wskaźnika unique_ptr trzeba najpierw załączyć do pliku nagłówek <memory>, który samą nazwą już sugeruje operacje na pamięci. Ten wskaźnik gwarantuje, że obiekt będzie miał tylko jednego właściciela (jeden wskaźnik odnoszący się do tego obiektu). Jednocześnie pozawala na przenoszenie własności na inne wskaźniki. Jednocześnie zawsze pozwalając na tylko jeden wskaźnik do obiektu. Kiedy wskaźnik wyłączny zostaje usunięty staje się wskaźnikiem pustym, albo zaczyna wskazywać na inny obiekt.

Klasa unique_ptr zastąpiła wprowadzoną w standardzie C++98 klasę auto_ptr, której użycie nie jest obecnie zalecane (z wyjątkiem starszych wersji kompilatorów, które nie obsługują standardu C++11). Jest ona przeznaczona do sytuacji, w których należy utworzyć a następnie usunąć nowy obiekt dla wykonania funkcji.

Klasa ta udostęnia interfejs z operatorem wyłuskania * (zwraca obiekt wskazywany) a także operator dostępu do składowej obiektu wskazywanego -> (w przypadku, gdy ów obiekt jest strukturą lub klasą). Wskaźnik unique_ptr nie implementuje arytmetyki wskaźnikowej, która jest przez często uznawana za źródło problemów programistycznych.

#include <iostream>
#include <string> 
#include <memory>

using namespace std; 

class ShortMessage{

   string message;
public:
   ShortMessage(const string s) : message(s){
   cout << "C++ message: obiekt utworzony." << endl;
   }

   ~ShortMessage(){
   cout << "C++ message: obiekt zniszczony." << endl;
   }

   void addition() const{
   cout << message << endl;
   }
}

int main(void){
   unique_ptr<ShortMessage> sm (new Report("Wskaznik unique_ptr dziala."));
   sm->addition();
}

Temat jest dosyć obszerny. Dlatego kolejne inteligentne wskaźniki omówimy w następnych wpisach.

1 Reply to “Intelignetne wskaźniki w C++11 – część 1”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *