|
Konteyner va uni qo‘llanilishi
|
bet | 48/131 | Sana | 16.06.2024 | Hajmi | 1,92 Mb. | | #264063 |
Bog'liq Tiplarni dinamik tarzdaKonteyner va uni qo‘llanilishi. Xotirada ko‘p hollarda merosxo‘r obʻyektlarini saqlovchi sinflar vujudga keladi. Ularning xotiradan o‘chirilishi bazaviy sinf bilan bog‘liqdir. Masalan, sinf bo‘lsin va tugun ichidagi matndan olingan mo‘rosxo‘rlari Node va Attribute hamda (char*) qatorlardan to‘ldirilgan. Yoki papkani qayta o‘qish va yana o‘zgartirishda, bir marta yuklanadi fayl menejeri fayllar va kataloglar ro‘yxati.
Yuqorida ko‘rsatilgandek, new operatoriga nisbattan delete operatori foydalanish qiyinroq va muammoliroq bo‘ladi. Bazaviy sinf obʻyekti bilan bog‘liq katta blokda merosxo‘r sinf obʻyektlari uchun xotira ajratish kerak. Bazaviy sinf obʻyektini yo‘q qilish paytida, destruktor odatdagidek, merosxo‘r sinf uchun chaqiriladi, lekin xotirani qaytarishingiz shart emas — bu katta blokda ozod qilinadi.
PointerBumpAllocator sinf yaratamiz. Bu sinf katta blokdan turli o‘lchamdagi qismlarni kesib tashlash va eskisi tugagach, yangi katta blokni tanlashga imkon beradi.
PointerBumpAllocator sinfining dastur fragmenti.
-
template class PointerBumpAllocator
{public: PointerBumpAllocator() : free(0) { }
void* AllocBlock(size_t block) {
// todo: lock(this)
block = align(block, Alignment); if (block > free) {
free = align(block, PageSize); head = GetPage(free);
} void* tmp = head;
| -
head = (char*)head + block; free -= block;
return tmp;
}
~PointerBumpAllocator() {
for (vector::iterator i = pages.begin(); i != pages.end(); ++i)
{VirtualFree(*i, 0, MEM_RELEASE);}
}
private: void* GetPage(size_t size) {
void* page = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
pages.push_back(page); return page;}
vector pages; void* head;
size_t free;};
typedef PointerBumpAllocator<> DefaultAllocator;
|
Nihoyat, new va delete operatorlari bilan childObject ni tuzamiz va berilgan allocator bilan murojaat qilamiz:
-
template struct ChildObject
{static void* operator new(size_t s, A& allocator) { return allocator.AllocBlock(s);}
static void* operator new(size_t s, A* allocator) { return allocator->AllocBlock(s);}
static void operator delete(void*, size_t) { }
|
-
static void operator delete(void*, A*) { } static void operator delete(void*, A&) { }
private:
static void* operator new(size_t s);
};
|
Child sinfiga o‘zgaruvchilarni qo‘shish uchun barcha eʻlonlarni new operatori orqali amalga oshirish kerak bo‘ladi. New operatori quyidagicha bo‘ladi.
-
new (… parametrlar… ) ChildObject (…konstruktor parametrlari… )
|
Qulaylik uchun A& va A* uchun new operatorlarni qo‘llaymiz.
-
node = new(allocator) XmlNode(nodename);
|
Agar allokator ajratuvchi sifatida qo‘shilsa, ikkinchisidan foydalanish qulayroq:
-
node = new(this) XmlNode(nodename);
|
Bundan tushinarli bo‘ladiki, ortiqcha belgilardan qochishda amallarni bo‘lish uchun ko‘rsatkich va havolalar konvertatsiya bo‘ladi.
Obʻyekt yaratishda qaysi New operatoridan foydalanganligiga qaramasdan, delete operatori yordamida o‘chirish amalga oshirilmaydi, kompilyatorning o‘zi standart delete operatoridan foydalanadi. Quyidagicha sintaktik asosida:
-
Agar ChildObject sinfi obʻyekti yoki uning merosxo‘ri obʻyektidan foydalanayotgan bo‘lsangiz, new istisno vaqtida operatoriga mos delete orperatori chaqiriladi. Shuning uchung bu obʻyektdan foydalanganda birinchi size_t parametrni void*ga o‘zgartirish lozim.
New operatorini private bo‘limiga joylashtirish, uni allokatorsiz ishlashaga ruxsat bermaydi.
|
| |