Najprostszy możliwy “sprytny” wskaźnik… ale czemu sprytny? Ano temu, że sam zwalnia pamięć, gdy “nadejdzie jego czas”…
Do czego mi się to przyda
Główne zastosowanie std::auto_ptr to zabezpieczenie się przed wyciekami pamięci. Już nie musisz usuwać każdego obiektu operatorem delete – obiekty usuną się same!
Jak to działa
Bardzo prosto. std::auto_ptr bierze pod opiekę nasz obiekt i sam usuwa go z pamięci w odpowiednim czasie. A kiedy jest ten “odpowiedni czas”? W momencie, kiedy sterowanie wychodzi poza zakres, w którym wskaźnik został zdefiniowany.
Przykład
Kod z wykorzystaniem zwykłego wskaźnika:
void example1() { // 1. tworzymy obiekt Bubble* bubble = new Bubble(); // 2. pracujemy z obiektem bubble->blowUp(); // 3. usuwamy obiekt delete bubble; }
Kod z wykorzystaniem sprytnego wskaźnika
void example2() { // 1. tworzymy obiekt auto_ptr bubble(new Bubble()); // 2. pracujemy z obiektem bubble->blowUp(); } // tutaj auto_ptr sam usunie nasz obiekt "bubble"
Jak widzisz, nie usuwamy już ręcznie obiektu. Spryny wskaźnik robi to za nas! Jednocześnie, korzystamy ze wskaźnika w dawny sposób. Fajne!
Co jeszcze mogę zrobić ze sprytnym wskaźnikiem
std::auto_ptr ma jeszcze kilka funkcji. Możesz:
-
Pobrać od niego obiekt, którym się opiekuje:
// 1. tworzymy obiekt pod opieką sprytnego wskaźnika auto_ptr<Bubble> auto_bubble(new Bubble()); // 2. pobieramy obiekt Bubble *bubble = auto_bubble.get();
Teraz masz dostęp do obietku poprzez sprytny wskaźnik auto_bubble, oraz poprzez goły wskaźnik bubble.
-
Odebrać mu opiekę nad obiektem:
// 1. tworzymy obiekt pod opieką sprytnego wskaźnika auto_ptr<Bubble> auto_bubble(new Bubble()); // 2. odbieramy sprytnemu opiekę nad obiektem Bubble *bubble = auto_bubble.release();
Teraz masz dostęp do obietku jedynie poprzez goły wskaźnik bubble. Uwaga – sam musisz zadbać o usunięcie obiektu, bo sprytny wskaźnik już się nim nie opiekuje!
-
Oddać pod jego opiekę inny obiekt:
// 1. tworzymy obiekt pod opieką sprytnego wskaźnika auto_ptr<Bubble> auto_bubble(new Bubble()); // 2. oddajemy pod opiekę sprytnego nowy obiekt auto_bubble.reset(new Bubble());
Uwaga – Poprzedni obiekt zostaje automatycznie zniszczony!
-
Przekazać opiekę innemu sprytnemu wskaźnikowi:
// 1. tworzymy obiekt pod opieką sprytnego wskaźnika auto_ptr<Bubble> auto_bubble1(new Bubble()); // 2. przekazujemy opiekę nad obiektem innemu sprytnemu auto_ptr<Bubble> auto_bubble2 = auto_bubble1;
Teraz auto_bubble2 posiada nasz obiekt, a auto_bubble1 ma NULL. Dlaczego? Bo gdyby oba opiekowały się naszym obiektem, to w pewnym momencie obiekt ten byłby usuwany dwa razy!
Do czego nie stosować std::auto_ptr
- do kontenerów STL. Przykładowo, vector<auto_ptr<int> > to niedobry pomysł. Porządna implementacja STL sprawi, że taka konstrukcja nawet nie przejdzie kompilacji! Gdyby jednak przeszła – wystrzegaj się jej. STL wymaga, aby obiekty mogły być kopiowane, a auto_ptr tylko przekazuje opiekę nad obiektem. Przez to, kiedy np. vector zrobi sobie kopię tymczasową jakiegoś swojego elementu, a potem ją usunie – usunie nasz jedyny obiekt!
- do przekazywania parametrów do funkcji. Przykładowo, void funkcja(auto_ptr<string>) to niedobry pomysł. Podobnie jak w poprzednim przypadku – zamiast skopiowania obiektu na stos, nastąpi przekazanie opieki nad nim do tymczasowego obiektu (parametru funkcji). Wraz z zakończeniem funkcji parametr zostanie usunięty i tym samym przepadnie nasz obiekt. Zobacz artykuł Niebezpieczny auto_ptr
Podsumowanie
I to tyle. Możesz już zacząć używać sprytnych wskaźników. Od dziś Twoje programy staną się lepsze, a Twoje życie – łatwiejsze ;)
PS. Klasa std::auto_ptr dostępna jest w nagłówku <memory>
September 22nd, 2012 on 21:16
W pierwszym przykładzie zauważylem “mały” błąd (ogromny, ale kompilator to wychwyci więc unikniemy “tragedii”):
w 4 linijce brakuje ‘*’:
[code lang=”c++”]
Bubble bubble = new Bubble();
Bubble *bubble = new Bubble();
[/code]