Деструктор. Конструктордың қателерін өңдеу

Деструктордың қызметі – Dispose функциясына объект экземпляры иелеген жадыны(Heap, «үйме») коррект босатуға көмектесу. Бұдан бөлек, деструктор денесінде әдетте объект деинициалицазиясы, яғни объектті жоюға дайындау бойынша да амалдар енгізіліп қойылады. Бұл, дербес жағдайда, объекттің «өмір сүру» кезінде оның динамикалықсұранысы бойынша қайсы бір берілгендері сақталынып қойылған жадыны босату.

Деструктор (Паскалда) объектті жоймайды, ал конструктор оны құрмайды. Деструктор мен конструктордың әрекеттері қарама-қайшы емес, бұлар іс-жүзінде бір-біріне қатысы жоқ мақсаттар үшін арналған арнайы тәсілдер.

Деструктор виртуальді болуы мүмкін. Әрі деструкторды виртуальді етуге кеңес беріледі, өйткені деинициализация әрекеті – реализациясы ішкікласстарда әдетте қайтаанықталатын, берілген объекттің барлық әртүрлілігі үшін шаблонды болатын,әрекеттің айқын мысалы.

Ол виртуалды ма, жоқ па, бұған байланыссыз Dispose-дың кеңейтілген шақыруында деструкторды қолдану әрдайым объект өлшемін VMT-дан алу кодын генерациялауға алып келеді. Осылай екен, онда деструкторды Dispose-ң кеңейтілген шақыруында қолданудан бұрын объект экземпляры конструктор арқылы инициалицазия жасалыныпқойылуы тиіс.

Деструкторды Dispose-дан бөлек шақыру қарапайым тәсілдің шақырылуымен бірдей.

Деструкторды жариялаған кезде procedure қызметші сөзінің орнына destructor сөзі жазылады. Реализациясын сипаттау кезінде де destructor сөзі қолданылады. Кез-келген тәсіл сияқты деструкторда да параметр бола алады. Егер деструктор виртуалды болса, онда ұрпақ-класстарда деструкторды қайтаанықтау кезінде параметрлер қатары дәлме-дәл сақталуы тиіс.

Мұраға алынған деструктор ішкікласста қайтаанықталу кезінде әдетте деструктордың жаңа реализациясы денесінің соңғы жағында шақырылады.

Класс тәсілдерінің құрамына әрдайым Done стандартты атауымен бір деструкторды енгізген және оны виртуалды деп жариялаған дұрыс. Бұл деструктордың денесі бос болуы да мүмкін.

Конструктордың қателерін өңдеу. FAIL операторы

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

Мысал:

Объект экземпляры кэш бойынша файлға қол жеткізуді қамтамасыз етеді және бұл үшін жадыдан үлкен көлемде(ондаған килобайт) буферді пайдаланады. Буфер конструктордың объектті құру барысында динамикалық бөлінеді. Бұл буфердің адресі өрістердің бірінде сақталады, деструктор осы жадыны босатады.Объект құрудан алдын жады объекттің өрістерін орналастыруға жеткілікті, ал буферді бөлуге жеткіліксіз. Бірақ, буферді конструктор бөледі, ал объект экземпляры үшін жады бөлетін new функциясының өзі дұрыс орындалады. Не істеу керек?

Бөлінуі мүмкін болған үздіксіз жады аймағының көлемін MaxAvail функциясын шақыру кезінде тексеруге болады. Одан үлкен көлемде жады бөлінбейді.

Конструктор өз ішінде Fail операторын шақыруы мүмкін. Оның нәтижесі келесі әрекеттерге әкеледі:

— конструктордың орындалуы аяқталады (конструктордан шығу орындалады);

— егер конструктор New функциясымен бірге шақырылса, онда объект экземплярына New арқылы бөлінген жады босатылады. Ал, New-ді инициализациялайтын көрсеткіш nil мәніне ие болады;

— егер орындалып жатқан конструктор мұрагер-класстың конструкторынан мұраға алынған тәрізді шақырылса, онда конструктор шақырып отырған тәсілге «жалған» (false) мәні қайтарылады.

Сонда объектті келесі үлгі (шаблон) бойынша тудырамыз:

p:=New(PObject, Init);

if p=nil then {обработка ошибки}

Мұраға алынған конструкторды шақыруды келесі үлгі бойынша құрамыз:

if not inherited Init then Fail;

Ал, буфер үшін жады бөлу конструкторда былай құрылуы мүмкін:

if MaxAvail>BufSize then

GetMem(Buffer, BufSize)

else

Fail;

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

Екінші жолы – бұл Mark және Release процедураларын қолдану