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í:
vytvořte třídu, která bude obsahovat daný ukazatel
napište konstruktory. Kopykonstruktor je nutné zakázat (přesunem do private sekce) – proč?
Napište destruktor (který odalokuje paměť, byla-li naalokovaná)
zakažte přiřazování (operátor =)
Napište konverzní operátor na ukazatel (který se bude využívat k tomu aby se třídou šlo pracovat jako se standardním ukazatelem
napište externí funkci Destroy, která zajistí odalokování paměti ukazatele.
rozšiřte (=učiňte univerzálním) tuto třídu na všechny typy ukazatelů pomocí šablon
je nutné rozlišovat alokaci jednoho prvku a pole? V případě, že ano vytvořte třídy pro jednotlivé varianty. Destroy navrhněte univerzálně pro obě třídy
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