piątek, 8 października 2010

Kosmici atakują [::) - Intrusive Smart Pointer

Nie pisałem jeszcze o tym, ale wydaje mi się że to ważne. Otóż w większej części silnika(szczególnie odnosi się to do różnych zasobów(np. obrazy, dźwięki, animacje, itp.)) korzystam z tzw. inwazyjnych inteligentnych wskaźników - nie są to jednak zielone ludki z kosmosu, ale bardzo pomocne i pożyteczne wskazówki. Wszystkie smart pointery mają jeden cel zabezpieczyć program przed wyciekami pamięci. 


W projekcie wykorzystuje ich wersję z BOOST(boost::intrusive_ptr), ogólnie założenie inwazyjnych wskaźników jest takie: 
- w klasie która ma korzystać z dobrodziejstwa tegoż wskaźnika musi być pole(zmienna, nasz intruz), która będzie licznikiem referencji(liczba wskaźników które wskazują dane miejsce w pamięci w którym znajduje się obiekt)
- trzeba też zdefiniować funkcje które będą operowały na liczniku(dodającą i odejmującą referencje)
- na koniec musimy stworzyć szablonowe funkcje o nazwach: intrusive_ptr_add_ref i intrusive_ptr_release.
Kod klasy Licznika referencji: 





#pragma once
#include


//! Klasa licznika referencji potrzebna do inteligentnego wskaźnika.
/*! 
 * Od tej klasy powinna dziedziczyć klasa, która chce korzystać z mechanizmu SmartPointer'a.
 */
class CRefCounter 
{
//! Licznik referencji.
uint m_References;


public:
//! Konstruktor zeruje licznik.
CRefCounter() : m_References(0) {}
virtual ~CRefCounter() {}


//! Dodaje referencje do wskaźnika
void AddRef()
{
++m_References;
}
//! Odejmuje referencje od wskaźnika
int Release()
{
--m_References;
return m_References;
}


        //! zwraca liczbę referencji
int GetRef()
{
return m_References;
}
};


// z tego korzysta boost przy dodawaniu referencji
template void intrusive_ptr_add_ref(T * p)
{
p->AddRef();
}
// z tego korzysta boost przy odejmowaniu referencji
template void intrusive_ptr_release(T * p)
{
if (p->Release() <= 0)
delete p;
}


Aby skorzystać teraz z Smart pointera musimy odziedziczyć po tej klasie(patrz powyżej) klasę która ma z niego korzystać :

CMyClass :public CRefCounter 
{
public:
    CMyClass() {cout << "Konstruktor CMyClass" << endl;}
    CMyClass() {cout << "Destruktor CMyClass" << endl;}
};

typedef boost::intrusive_ptr CMyClassPtr;

int main()
{
    CMyClassPtr p1(new CMyClass); ref = 1 // komunikat konstruktora
    CMyClassPtr p2(p1); // ref = 2
    CMyClassPtr p3 = p2;  // ref = 3

    // powinny być trzy trójki
    cout << p1->GetRef() << " " << p2->GetRef() << " " << p3->GetRef() << endl;
    
//komunikat destruktora
     cin.get();
    return 0;
}

Jak widać Inwazyjny Smart nie jest trudny w zastosowaniu, jest też wydajny i wygodny. 

Jeśli gdzieś zrobiłem błąd, albo coś jest niejasne to piszcie w komentarzach.

Brak komentarzy:

Prześlij komentarz