Дістемелік кешен


New және delete операторларын қайта анықтау



бет24/112
Дата22.12.2021
өлшемі0,85 Mb.
#127596
түріПрограмма
1   ...   20   21   22   23   24   25   26   27   ...   112
Байланысты:
ооп лекция
қорытынды атт 11.03.21, қорытынды атт 11.03.21, эссеге керек
6. New және delete операторларын қайта анықтау

Жадыны басқарудың балама нұсқаларын қамтамасыз ету үшін обьектіге динамикалық жадыны және сәйкесінше обьект массивтерін бөлуге new және new [ ] операторларының , сонымен қатар delete және оны босату үшін delete [] операцияларының өзіндік нұсқаларын анықтауға болады. Бұл функция-операторлар келесі ережелерге сай болуы тиіс:



  • Оларға класс типінің параметрлерін беру қажет емес;

  • new және new [ ] функцияларына бірінші параметр болып size_t типті обьектінің көлемі жіберілуі тиіс ( бұл sizeof операторымен қайтарылатын тип, ол тақырыптық файлда анықталады); шақырған кезде ол функцияларға түсініксіз түрде жіберіледі;

  • return сілтегішті өзге типтерге қайтарып тұрса да, олар void* мәнінің қайтарылатын типімен анықталуы керек;

  • delete операторы void қайтарымының типіне және void* типінің бірінші аргументіне ие болу керек;

  • Жадыны бөлу және босату оперторлары класстың статистикалық элементтері болып табылады.

Қайта анықталған операторлар әрекеті олармен жасырын түрде орындалатын әрекеттерге сай келуі тиіс. New операторы үшін бұл ол дұрыс мағынаны қайтаруы керек, нөлдік көлемдегі жадты бөлуге сұранысты корректілі түрде өңдеп және сұранысты орындау мүмкіншілігі болмаған кеэде шығарып тастап отыруды білдіреді. Delete операторы үшін нөлдік сілтегішті жою қауіпсізболуы керек екендігін ескерген жөн, сондықтан оператор ішінде сілтегішті нөлге және тепе-теңдік жағдайындағы кез-келген әрекеттің жоқ екендігіне тексеру жүргізу керек. Жадыны бөлудің және босатудың қалыпты операторлары класстың әрекет облысында қайта анықталғандармен бірге қолданылуы мүмкін ( көрінетін облысқа кіретін операторлар көмегімн : : (осы класс және өзгелері үшін де).

Жадыны бөлу операторын қайта жүктеу жадыны үнемдеу үшін,бағдарламаның тез жұмыс жасауы және мәліметтерді кейбір белгілі бір облыстарға орнату үшін қолданылады. Мысалы, кейбір обьектіге сілтегіші бар класс сипатталсын:

class Obj { … };

class pObj {

private:


Obj *p;

};

p0bj типіндегі обьект астына new қалыпты операторының көмегімен жадыны бөлу кезінде



pObj *p = new pObj;

байттардың нақтылы көлемі sizeof(p0bj) асып кетеді, себебі new , әдетте бөлінетін облыстың басына оның көлемін жазып кетеді ( delete операторларын дұрыс өңдеу үшін).

Шағын обьектілер үшін бұл накладты шығындар маңызды болуы мүмкін. Жадыны үнемдеу үшін жадының үлкен блогын бөліп отыратын, кейін онда 0bj сілтегіштерді орнататын өзіндік p0bj классты new операторын жазуға болады. Бұл үшін p0bj обьектісіне head0free статикалық жолы енгізіледі, онда келесі обьектіні орнатуға арналған блоктың бірінші бос ұяшығына сілтегіш сақталады

Қолданылмайтын ұяшықтар тізімге жиналады. Байланыс жолының астында жадты алмау үшін, бірлестік қолданылады ( union), оның көмегімен бір ұяшық не обьектіге сілтеуішті орнату үшін, не келесі бос ұяшықпен байланыс үшін қолданылады:

class pObj {

public:


static void * operator new(size_t size);

private:



union {

Obj *p / / обьектіге сілтеуіш

pObj *next; / /келесі бос ұяшыққа сілтеуіш

};

static const int BLOCK_SIZE; / / блок колемі



// бос ұяшықтар тізімінің атауы

static pObj *headOfFree;

};

void * pObj: :operator new(size_t size) {



// жадының дұрыс емес көлемінің сұранысын қайта бағыттау

//new қалыпты операциясы

If (size != sizeof(pObj)) return : :operator new(size);

pObj *p = headOfFree; // бірінші бос ұяшыққа сілтегіш

//бос ұяшықтар тізімінің сілтегішінің орнын өзгерту

If (p) headOfFree = p ­­­-> next;

// егер бос жады болмаса, кезекті блокты бөлім аламыз:

else {


pObj *newblock =static_cast

( : :operator new(BLOCK_SIZE * sizeof(pObj)));

// біріншіден басқа барлық ұяшыұтар бос емес (ол

//бос болмайды). Оларды жинаймыз:

for (int i= 1; i< BLOCK_SIZE - 1; ++i)

newblock[ i ].next = &newblock[ I + 1 ];

newblock[BLOCK_SIZE - 1 ].next = 0;

//бос ұяшықтар орнатамыз:

headOfFree = &newblock[ 1 ];

p =newblock;

}

return p; // Сілтегішті бөлінген жадыға қайтарамыз



}

Қайта анықталған new операторы мұраға беріледі, сондықтан ол туынды обьектілер үшін шақырылады. Егер олардың көлемдері базалық көлемге сай келмесе, бұл ашық жер қалдыруы мүмкін. Оларды болдырмау үшін оператор басында көлемнің сәйкестігі тексеріледі. Егер обьект көлемі new операторы қайта шақырылған көлемге сәйкес келмесе, жадыны бөлуге сұраныс new қалыпты операторына жіберіледі.

p0bj класын қолданатын бағдарламада оның статикалық жолдарының инилизациясы болуы тиіс:

pObj *pObj : :headOfFree; // 0 ге жасырын түрде қойылады

const int pObj: :BLOCK_SIZE = 1024;

Бұл мысалдан көріп отырғанымыздай, жадыны үнемдеуден басқа жоғары тез әсер етуге де қол жеткіземіз. Себебі көп жағдайда жадыны бөлу бірнеше қарапайым операторларға түсіріледі.

Әрине, егер new операторы қайта анықталса, delete операторы үшін де дәл солай болу керек ( мысалы, біздің жағдайымызда delete қалыпты операторы обьект басында оның көлемі туралы дұрыс мәліметті таба алмауы мүмкін, бұл бағдарламаның нақтылы емес әркет етуіне алып келеді).

Void pObj: :operator delete(void * ObjToDie. Size_t size) {

if (ObjToDie == 0) return;

if (size != sizeof(pObj)) {

: :operator delete(ObjToDie); return;

}

pObj *p = static_cast


(ObjToDie);

p->next = headOfFree;

headOfFree = p;

}

Delete операторында обьектілер көлемінің сәйкестігінің тексерісі оындалған, ол new операторында келтірілгенге бара-бар.





Достарыңызбен бөлісу:
1   ...   20   21   22   23   24   25   26   27   ...   112




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет