Ko‘rsatkichlar



Yüklə 117,5 Kb.
səhifə4/7
tarix16.06.2023
ölçüsü117,5 Kb.
#131322
1   2   3   4   5   6   7
KO

Heap


Heap ham xotiraga qiymat yozish usuli deyishim mumkin. U odatda stackdan farqli ravishda OS ishga tushganda RAM ga joylanadi(Gap ma’lumotlar tuzilmalaridagi heap haqida emas), har bir dastur uchun alohida beriladi.

  • OS ishga tushganda RAMdam joy oladi

  • Hajmi stackka qaraganda anchagina katta bo’ladi, dinamik kengaya oladi

  • Ko’p zamonaviy OSlarda, har bitta protsess o’zining alohida heap xotirasiga ega bo’ladi

  • Qiymatlar kiritilishi stackka qaraganda sekinroq

  • Dinamik obyektlar undan joy oladi

  • Qiymatlar xotiradan iyerarxik va tasodifiy tarzda joy oladi

  • Unga qiymat joylash va o’chirish dasturchi zimmasiga yuklatiladi

  • Ko’pgina zamonaviy OSlarda va ko’p hollarda, dastur ishini tugatgach, heapga joylagan qiymatlari o’chib ketadi

Heap shunchaki(mantiqiy) xotira bo’lib, RAM ning bir qismi heap sifatida ishlatilishi mumkin. RAMning bir qismini heap sifatida ishlatishni OSga qo’yib bering, bizni dinamik o’zgaruvchilar qiziqtiradi.

Heapdagi iyerarxik joylashuv, stackoverflowdagi Martin Liversage javobidan olindi: https://stackoverflow.com/a/1213360
Eng birinchi yozgan yuqoridagi kodimizning main funksiyasi ichiga kichik o’zgartirish kiritamiz:
Test *t = new Test();
return 0;

Hech narsa chiqmadimi? Chunki biz obyektimizni dinamik tarzda joylayapmiz, shunday ekan uni o’zimiz o’chirishimiz kerak bo’ladi. Lekin deyarli barcha zamonaviy OSlar dastur ishini yakunlagach unga ajratilgan heap ni tozalaydi, lekin dastur ishini yakunlab bo’lgach tozalashni OS qilgani uchun bizga “Obyekt o’chirildi” degan yozuv chiqmaydi.

b stackka yozilgan qiymatga ko’rsatkich bo’lib, heapdagi manzilni o’zida saqlashi

Qiymatlarni heapga joylash va o’chirish


Biz heapga qiymat joylash uchun yuqoridagi kabi o’zgaruvchini initializatsiya qilib olamiz. E’tibor bering: new kalit so’zi yordamida obyektni konstruktoriga murojaat qilyapmiz, so’ngra u heapga joylanyapti. Obyekt heap ga joylanadi, unga ko’rsatkich stackda turadi. Buni stackning yuqorida aytilgan “qo’shnilik” xususiyatini bilgan holda test qilish uchun kod yozsakchi?
int a;
int *b = new int(6);
cout<<”a ning manzili: “<<&a<cout<<”b ning manzili: “<<&b<cout<<”b ko’rsatkich bo’lib turgan obyektning heap dagi manzili: “<
bundan siz a va b ning qo’shni ekanligini va b ulangan heapdagi obyekt manzilini ko’rasiz, masalan mening holatimda bu quyidagicha:

Agar bitta obyektni yoki massivni heapga joylamoqchi bo’lsangiz
long long int *son = new long long int(5);//bitta son uchun
long long int *sonlar = new long long int[10];//massiv uchun


  • E’tibor bering, yuqorida new kalit so’zi yordamida joylanganda konstruktor ishga tushadi dedik. N o’lchamli massivni joylaganimizda ham o’sha tipdagi qiymatlar uchun N marta konstruktor ishga tushib, heapga qiymatlar joylanadi.

Yoki avval ko’rsatkich ochib, keyinroq heapga qiymat joylab boyagi ko’rsatkichga biriktirib olsangiz ham bo’ladi:
long long int *son = NULL;
son = new long long int(1234);

Ko’rsatkich orqali heapdan qiymat olishda ko’rsatkich nomi oldiga yulduzcha(*) belgisini yozishimiz kerak:
cout<<*son;
cout<*son = 1234; shaklida yozish orqali qiymatini o’zgartiramiz.

  • Ko’rsatkichni ko’rsatkichga qiymat sifatida berish quyidagicha:

int* a = new int(4), *b = new int(5);
a = b;//albatta bunda biri o’zgarishi ikkinchisiga ta’sir qiladi
//chunki ular ko’rsatayotgan heapga manzil bir xil
//alohida bo’lsin desangiz *a = *b deyishingiz mumkin masalan


  • Joylagan obyektimiz ichidagilarga ko’rsatkich(->, inglizchasiga arrow) orqali murojaat qilamiz:

class Obj{
public:
int a, b;
Obj(){a = 2; b = 3;}
};
int main(){
Obj *var = new Obj();
cout<a;//2
delete var;
return 0;
}


  • Heapdan bitta qiymat o’chirish uchun delete, massivni o’chirish uchun esa delete[] ishlatiladi. delete bitta obyekt uchun desktruktorga murojaat qilib, uni xotiradan o’chirsa, delete[] massivdagi har bir element uchun destruktorini ishlatib, elementlarni o’chirib tashlaydi.

O’chirish yoki tozalash so’zlari aslida xotiradagi manzilni yo’q qilib yuborishni anglatmaydi. delete bilan siz OSga “brat, bu manzildan foydalanib bo’ldim, endi bo’shadi, uni boshqalarga berishingiz mumkin” deb bildirgan bo’lasiz.
class Test{
public:
int a,b,c;
Test(){cout<<”Obyekt xotiraga kiritildi\n”;}
~Test(){cout<<”Obyekt o’chirildi!\n”;}
};
int main(){
Test *t = new Test[2];//2 marta konstruktor ishga tushadi
delete t;//1 ta destruktor ishlaganini ko’ramiz. delete[] bilan o’chirish kerak
return 0;}

delete yordamida heap tozalanadi, lekin ko’rsatkich stackdaligi uchun unga ta’sir o’tkazmaydi.
Bir qator bilan bir nechta dinamik obyektlarni o’chirish uchun
delete a,b,c;//massivlar uchun delete[] ishlatgan ma’qul
kabi yoziladi.
Yana bir qiziq holat ko’rsataman:
long long int a = 7;
long long int *b = &a;//bunda b a ga ko’rsatkich bo’lib qoladi
delete b;
cout<<*b;

Kodni avval yozib, yurgazib ko’ring. Shunda b hali ham 7 ekanligini ko’rasiz. Nega bunday bo’ldi? Sababi biz b ga manzil ko’rsatayotganda unga heapdagi manzilni emas, stackdagi manzil(a ning manzili)ni berdik. Bunda stackdagi qiymat o’chirilmaydi, o’zi shundog’am dastur ishini tugatgach o’chib ketadi.

  • Funksiyalar ham ko’rsatkich qaytarishlari mumkin. Ko’rsatkich qaytaradigan funksiyalarni yozish uchun sintaksis quyidagicha:

tur* funksiya_nomi(/*parametrlar*/){
//kodlar
return ko’rsatkich;
}

Agar sizdagi biror class ichida dinamik obyekt bo’lsa, siz o’sha class tipida dinamik obyekt e’lon qilsangiz, unda class ichidagi destruktor bilan class ichidagi dinamik obyektlarni tozalash kerakmi? O’ylab ko’ring
Ko’rsatkichlar heapga manzil saqlashi kerak, ularning stackdagi o’lchami 32-bitlik OSlarda odatda 4 baytlik bo’ladi, chunki bu xotiraning manzillanishi bilan bog’liq. 64 bitlik OSlarda ko’rsatkichlar stackdan 8 baytlik joyni band qiladi.

Yüklə 117,5 Kb.

Dostları ilə paylaş:
1   2   3   4   5   6   7




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©azkurs.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin