Zapouzdřený ukazatel



Vytvořte třídu pro práci s ukazateli, která umožní práci s ukazatelem tak, aby byla co nejvíce podobná standardní práci s ukazatelem, ale aby automaticky odalokovávala paměť, pokud tak neučiní uživatel.



Třída by měla pracovat tak, že zapouzdří ukazatel, a umožní s ním dále standardně pracovat. Nevýhodou práce s ukazateli (kterou má tento mechanizmus „vylepšit“) je to, že je nutné naalokovanou paměť odalokovat. To vadí například při volání výjimek, které toto odalokování neřeší. Proto navrhněte jednoduchou třídu, která je schopna odalokovat samostatně paměť (jelikož na každý objekt i při volání výjimek volán destruktor), přitom ale zachová co nejvíce původních vlastností ukazatele.

Tento ukazatel se bude používat pouze pro paměť, kterou alokujeme. Pro paměť odkazovanou bez alokace se bude používat standardní ukazatel.

Omezení: nesmí být přiřazen jinému zapouzdřenému ukazateli, nesmí být předáván z funce do nadřazené funkce



Řešení:









Poslední úpravy 2008-07-30







































// void Test(Zapuk<double[]> tst) {}
void Testref(Zapuk<double[]> &tst) {}

int main(int argc, char* argv[])
{
{
Zapuk<double[]> ukazatel(new double[10]);
Zapuk<int *[]> ukazateli(new int*[10]);
Zapuk<int *> ukazatelii(new int*);
// Test (ukazatel); // nelze zalozit kopie prvku jako kopy konstruktor
Testref(ukazatel);
*ukazatel = 5;
*(ukazateli+5) = 0;
Destroy(ukazatelii);
// ukazatelii.~Zapuk<int *>();
delete ukazatelii; // odalokuje „vnitřní“ ukazatel díky konverznímu
// lépe je delete přetížit – a ještě lépe napsat funkci Destroy
ukazatelii = 0; // tohle nastaví „vnitřní“ ukazatel na NULL
double b;
b = *ukazatel;
ukazatel[0] = 4;
b = ukazatel[0];
}
return 0;
}



#ifndef zap_ukH
#define zap_ukH
// ukazatel spojený s alokací prostoru pomocí new, ci new [] ve volání
// odkazy bez new se řeší klasickými ukazateli
// vkládání ukazatele musí být spojeno s new !!!
// není potřeba explicitně dealokovat, a funguje s výjimkami, jinak je potřeba
// se k němu chovat jako k normálnímu ukazateli

// volání Zapuk<Typ_ukazatele> nazev_proměnne(new Typ_ukazatele)
// Zapuk<double> ukazatel(new double)

// sablona pro ukazatel na jeden prvek
template <typename T>
class Zapuk {
T * const uk;
Zapuk(Zapuk<T>&) {} // nutno zakázat - musí být spojeno s alokací
Zapuk& operator = (const Zapuk&) {} // musí být také spojeno s alokací
public:
Zapuk (T *puk) {uk=puk;}
~Zapuk (void) {if (uk) delete uk; uk = 0;}
operator T* (void) {return uk;}
// void operator delete (void * ptr) {::delete (T*)(ptr);}
};



// volání Zapuk<Typ_ukazatele []> nazev_proměnne(new Typ_ukazatele[pocet_prvku])
// Zapuk<double []> ukazatel(new double[10])
// sablona pro ukazatel drzici pole
template <typename T>
class Zapuk<T[]> {
T * uk;
Zapuk(Zapuk<T[]>&){}
Zapuk& operator = (const Zapuk&) {} // musí být také spojeno s alokací
public:
Zapuk (T *puk) {uk=puk;}
~Zapuk (void) {if (uk) delete[] uk;uk=0;}
operator T* (void) {return uk;}
};

// funkce pro odalokování paměti volající destruktor, určená pro
// explicitní destrukci paměti zapouzdřeného ukazatele
template <typename R>
inline void Destroy (R &tt) {tt.~R();}

#endif