Sunteți pe pagina 1din 22

Programare orientata pe obiecte

Curs 14 – Smart pointers

C
++{};
C++ Acest curs
› Introducere smart pointers
› Exemplu de implementare a unui smart pointer
› unique_ptr, shared_ptr, weak_ptr
› Subiect examen 2017 - 2018
C++ Introducere
› Programele C++ gestioneaza memoria dinamica cu new si delete
in acelasi stil mostenit din limbajul C
› Programele moderne (Python, Java & C#) gestioneaza memoria
prin intermediul unei tehnici numite garbage collection
› In astfel de limbaje doar se apeleaza new sau un echivalent,
eliberarea memoriei fiind realizata de garbage collection atunci
cand programul nu mai foloseste obiectele allocate dinamic
› Garbage collection adauga un overhead – consum de memorie
mai mare, cod suplimentar, afecteaza eficienta la run tine.
› Din acest motiv C++ nu ofera garbage collection
C++
› Limbajele GB in mod tipic aloca toate obiectele in heap
gestionand astfel memoria intr-o maniera uniforma
› C++ suporta statically-allocated si stack-allocated
objects, precum si heap-allocated objects.
› Heap allocation este putin mai lenta iar fragmentarea
memoriei heap poate degrada performantele programului.
› C++ urmeaza sloganul “You only pay for what you use”
insemnand ca programele care nu au nevoie de heap nu sunt
“penalizate” (costul aferent utilizarii nu apare la run time).
C++
› Totusi C++ furnizeaza atat beneficiile unui program non GB
cat si cele ale unui program GB atunci cand este necesar.
Metodele puse la dispozitie pentru gestiunea automata a
memorie dinamice sunt:
– apelul delete in destructor
– utilizarea unor functii globale make(…) respectiv destroy(…) sau a
unor obiecte allocator cu metodele (allocate, deallocate
etc.) care implementeaza alocarea si dealocarea memoriei (este
eliminat astfel apelul direct al operatorilor new si delete)
– utilizarea smart pointers
C++ Smart pointers
› Pointeri care “stiu” exact cand sa dealoce memoria referita.
› Sunt definiti printr-o clasa “ambalaj” peste un pointer normal
(precum clasa iterator) ce are operatori ca * si ->
supraincarcati
› Obiectele unor astfel de clase “arata” ca pointeri normali dar
pot face multe lucruri: eliberarea automata a memoriei,
contorizare referinte etc.
C++ Utilizare clasica a unui pointer
int main(void)
{
char* pName = new char[1024];

SetName(pName);


if (null != pName)
{
delete[] pName;
}
}
class Person
{
int age;

C++ char* pName;


public:
Person() : pName(0), age(0){}
Person(char* pName, int age) : pName(pName), age(age){}
~Person(){}

void Display()
{
cout << "Name = " << pName << " Age " << age << endl;
}
void Shout()
{
cout << "Ooooooooooooooooo";
}
};

void main()
{
Person* pPerson = new Person("Gica Popescu", 22);
pPerson->Display();
delete pPerson;
}
#include<iostream>
using namespace std;
Smart pointer
C
++ class SmartPtr
{
int *ptr; // Actual pointer
public:
// constructor de initializare/conversie
// de remarcat utilizarea cuvantului cheie explicit
explicit SmartPtr(int *p = NULL) { ptr = p; }

// Destructor
~SmartPtr() { delete(ptr); }

//supraincarcarea operatorului *
int &operator *() { return *ptr; }
};

int main()
{
SmartPtr ptr(new int());
*ptr = 20;
cout << *ptr;
return 0;
}
template <class T>
class SmartPtr
{
C++ T *ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T *p = NULL) { ptr = p; }

// Destructor
~SmartPtr() { delete(ptr); }

// Overloading dereferncing operator


T & operator * () { return *ptr; }

// supraincarcarea operatorului -> astfel incat membrii T sa poate fi accesati


// in aceeasi maniera oferita de un pointer normal
T * operator -> () { return ptr; }
};
int main()
{
SmartPtr<int> ptr(new int());
*ptr = 20;
cout << *ptr;
return 0;
}
C++

int main()
{
SmartPtr<Person> ptr(new Person(“Gica Popescu " , 22));
ptr->Display();
return 0;
}
C++ Contorizarea referintelor
class RefCounter
{
int count; // contor de referinte
public:
RefCounter (){ count = 0; }
// Incrementare contor de referinte
void AddRef() { count++; }

// Decrementare contor de referinte


int Release(){ return --count; }
};
C++ Contorizarea referintelor
template < typename T >
class SmartPtr
{
T* ptr; // pointer la data
RefCounter* reference; // contor referinte
public:
SmartPtr();
explicit SmartPtr(T* p);
SmartPtr(const SmartPtr<T>& sp);
~SmartPtr();
T& operator* () { return *ptr; };
T* operator-> () { return ptr; };
SmartPtr<T>& operator = (const SmartPtr<T>& sp);
};
template<class T>
SmartPtr<T>::SmartPtr() :ptr(0), reference(0)
{
C++ // creaza un obiect RefCounter
reference = new RefCounter();
// incrementeaza counterul de referinte
reference->AddRef();
}

template<class T>
SmartPtr<T>::SmartPtr(T* p): ptr(p), reference(0)
{
// creaza un obiect RefCounter
reference = new RefCounter();
// incrementeaza counterul de referinte
reference->AddRef();
}

template<class T>
SmartPtr<T>::SmartPtr(const SmartPtr<T>& sp): ptr(sp.ptr), reference(sp.reference)
{
// Copiaza adresa continuta de ptr si adresa continuta de pointerul reference
// incrementeaza counterul de referinte
reference->AddRef();
}
C++
template<class T>
SmartPtr<T>::~SmartPtr()
{
// decrementeaza counterul de referinte
// daca referinta este zero dealoca data si obiectul referinta
if (reference->Release() == 0)
{
delete ptr;
delete reference;
}
}
template<class T>
SmartPtr<T>::SmartPtr<T>& operator = (const SmartPtr<T>& sp)
C++ {
if (this != &sp) // evita auto asignarea
{
// decrementeaza counterul de refinte curent
// daca refeinta devine zero sterge data si referinta
if (reference->Release() == 0)
{
delete ptr;
delete reference;
}

// copiaza data pointerul referinta


// incrementeaza counterul de referinte
ptr = sp.ptr;
reference = sp.reference;
reference->AddRef();
}
return *this;
}
C++ void main()
{
SmartPtr<Person> p(new Person("Gica Popescu", 22));
p->Display();
{
SmartPtr<Person> q = p;
q->Display();
// q, apel destructor

SmartPtr<Person> r;
r = p;
r->Display();
// r, apel destructor
}
p->Display();
// p, apel destructor
//apel delete Person
}
C++ Aplicatii: memory leaks
› Fie urmatoarea secventa de cod:
void MakeNoise()
{
Person* p = new Person("Gica Popescu", 22);
p->Shout();
delete p;
}

› Daca Shout() arunca o exceptie, delete p nu va mai fi


apelat
C++ Aplicatii: memory leaks
› Solutie:
void MakeNoise()
{
Person* p = new Person(“Gica Popescu", 22);
try
{
p->Shout();
}
catch (...)
{
delete p;
throw;
}
delete p;
}
› Exemplu considerat rezolva problema insa adauga un overhead
(cod suplimentar executat) cu prinderea si rearuncarea exceptiei
C++ Aplicatii: memory leaks
› Alternativa:

void MakeNoise()
{
SmartPtr<Person> p(new Person(“Gica Popescu", 22));
p->Shout();
}
C++ Clase smart pointers in STD
› std::unique_ptr
– nu are counter de referinte
– nu are constructor de copiere
– nu are operator de asignare (de copiere)
– are constructor de mutare
– are operator de asignare de mutare
http://www.cplusplus.com/reference/memory/unique_ptr/
› std::shared_ptr
– exemplul prezentat in curs
http://www.cplusplus.com/reference/memory/shared_ptr/
› std::weak_ptr
– nu incrementeaza contorul de referinte al unui shared_ptr
– expired()
– lock()
http://www.cplusplus.com/reference/memory/weak_ptr/
C++

S-ar putea să vă placă și