34 / 90

C++ Memory Management: new & delete

C++ xotirani boshqarish: new va delete

C++ bizga xotirani ish vaqtida dinamik ravishda taqsimlash imkonini beradi. Bu dinamik xotira ajratish deb nomlanadi.

Java va Python kabi boshqa dasturlash tillarida kompilyator o'zgaruvchilarga ajratilgan xotiralarni avtomatik ravishda boshqaradi. Lekin bu C++ da bunday emas.

C++ da biz o'zgaruvchidan foydalana olmagach, dinamik ravishda ajratilgan xotirani qo'lda ajratishimiz kerak.

Biz mos ravishda new va delete operatorlari yordamida xotirani dinamik ravishda ajratishimiz va keyin ajratishimiz mumkin.

C++ yangi ifodasi

Xotirani ish vaqtida ajratish uchun new ifodasidan foydalanishimiz mumkin. Masalan,

example.cpp
// int ko'rsatkichini e'lon qiling
int* point_var;

// xotirani dinamik ravishda taqsimlash
// new kalit so'zidan foydalanish
point_var = new int;

// ajratilgan xotiraga qiymat belgilash
*point_var = 45;

Bu erda biz new ifodasi yordamida int o'zgaruvchisi uchun xotirani dinamik ravishda ajratdik.

E'tibor bering, biz xotirani dinamik ravishda ajratish uchun point_var ko'rsatkichidan foydalanganmiz. Buning sababi, new ifodasi xotira joylashuvi manzilini qaytaradi.

Shuningdek, biz xotirani ajratishimiz va qiymatni bir xil bosqichda ishga tushirishimiz mumkin:

example.cpp
// xotirani dinamik ravishda taqsimlash
// va qiymat tayinlang
int* point_var = new int{45};

Ushbu sintaksisdan foydalanish ishga tushirilmagan ko'rsatkichlardan qochadi. Ishlatilmagan ko'rsatkichlar o'chirilganda noaniq xatti-harakatlarga olib kelishi mumkin. Shunday qilib, bu afzal qilingan sintaksis.

new ifodasini ishlatish sintaksisi:

example.cpp
data_type* pointer_variable = new data_type{value};

ifodani o'chirish

Biz dinamik ravishda e'lon qilgan o'zgaruvchidan foydalanishimiz kerak bo'lmagandan so'ng, biz o'zgaruvchi egallagan xotirani bo'shatishimiz mumkin.

Buning uchun biz delete ifodasidan foydalanishimiz mumkin. U xotirani operatsion tizimga qaytaradi. Bu xotirani ajratish deb nomlanadi.

delete ifodasi sintaksisi:

example.cpp
delete pointer_variable;

Keling, bir misolni ko'rib chiqaylik.

example.cpp
// xotirani dinamik ravishda taqsimlash
// va int o'zgaruvchisini tayinlang
int* point_var = new int{45};

// xotirada saqlangan qiymatni chop etish
cout << *point_var; // Chiqish: 45

// xotirani ajrating
delete point_var;

// ko'rsatgichni nullptr ga o'rnating
point_var = nullptr;

Bu erda point_var ko'rsatkichidan foydalangan holda int o'zgaruvchisi uchun dinamik ravishda ajratilgan xotira mavjud.

Point_var tarkibini chop etgandan so'ng, biz xotirani delete yordamida ajratdik.

Agar ko'rsatkich o'chirilsa, aniqlanmagan xatti-harakatlarning oldini olish uchun xotirani ajratgandan so'ng ko'rsatgichni nullptr ga o'rnatish yaxshi amaliyotdir.

[!NOTE] Xotirani to'g'ri taqsimlamaslik xotiraning oqishiga olib kelishi mumkin, bu esa o'z navbatida dasturning katta hajmdagi xotirani iste'mol qilishiga olib keladi. delete ifodasidan to'g'ri foydalanish xotira oqishini oldini olish va xotirani samarali boshqarishni ta'minlash uchun muhim ahamiyatga ega.

1-misol: C++ dinamik xotirani ajratish

example.cpp
#include <iostream>
using namespace std;

int main() {

    // xotirani dinamik ravishda taqsimlash
    int* point_int = new int{45};
    float* point_float = new float{45.45f};

    cout << *point_int << endl;
    cout << *point_float << endl;

    // xotirani ajrating
    // ko'rsatkichlarni nullptr ga o'rnating
    delete point_int;

    delete point_float;
    
    return 0;
}

Chiqish

kod
45
45.45

Ushbu dasturda biz int va float turdagi ikkita o'zgaruvchiga xotirani dinamik ravishda ajratdik.

Ularga qiymatlarni belgilab, ularni chop etgandan so'ng, biz nihoyat delete ifodasi yordamida xotiralarni ajratamiz.

[!NOTE] Dinamik xotira taqsimoti xotirani boshqarishni yanada samaraliroq qilishi mumkin, ayniqsa massivlar uchun, biz ko'p marta ish vaqtigacha massiv hajmini bilmasligimiz mumkin.

2-misol: C++ yangi va massivlar uchun ifodani o'chiring

example.cpp
// n ta talabaning GPA ni saqlash va uni ko'rsatish uchun C++ dasturi
// bu yerda n – foydalanuvchi kiritgan talabalar soni

#include <iostream>
using namespace std;

int main() {

    int num;
    cout << "Enter total number of students: ";
    cin >> num;
    float* ptr;
    
    // float sonining xotirani taqsimlash
    ptr = new float[num];
    
    cout << "Enter GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": ";
    cin >> *(ptr + i);
    }
    
    cout << "\nDisplaying GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": " << *(ptr + i) << endl;
    }
    
    // ptr xotirasi chiqariladi
    delete[] ptr;
    ptr = nullptr;
    
    return 0;
}

Chiqish

kod
Enter total number of students: 4
Enter GPA of students.
Student1: 3.6
Student2: 3.1
Student3: 3.9
Student4: 2.9

Displaying GPA of students.
Student1: 3.6
Student2: 3.1
Student3: 3.9
Student4: 2.9

Ushbu dasturda biz foydalanuvchidan talabalar sonini kiritish va uni num o'zgaruvchisida saqlashni so'radik.

Keyin, biz yangi yordamida float massivi uchun xotirani dinamik ravishda ajratdik.

Ko'rsatkich belgilaridan foydalanib, biz ma'lumotlarni massivga kiritamiz (va keyinchalik ularni chop etamiz).

Bizga massiv kerak bo'lmagandan so'ng, kod yordamida massiv xotirasini ajratdik:

example.cpp
delete[] ptr;.

delete dan keyin [] dan foydalanishga e'tibor bering. Xotirani ajratish massiv ekanligini ko'rsatish uchun [] kvadrat qavslardan foydalanamiz.

3-misol: C++ yangi va Ob'ektlar uchun ifodani o'chirish

example.cpp
#include <iostream>
using namespace std;

class Student {
    private:
    int age;
    
    public:
    
    // konstruktor yoshni 12 ga kiritadi
    Student() : age(12) {}
    
    void get_age() {
      cout << "Age = " << age << endl;
    }
};

int main() {

    // talaba ob'ektini dinamik ravishda e'lon qilish
    Student* ptr = new Student();
    
    // get_age() funksiyasini chaqiring
    ptr->get_age();
    
    // ptr xotirasi chiqariladi
    delete ptr;
    
    return 0;
}

Chiqish

kod
Age = 12

Ushbu dasturda biz xususiy o'zgaruvchan yoshga ega bo'lgan Student sinfini yaratdik.

Biz default constructor Student() da 12 yoshini ishga tushirdik va uning qiymatini get_age() funksiyasi bilan chop etdik.

main() da biz new ifodasi yordamida Student ob'ektini yaratdik va uning manziliga ishora qilish uchun ptr ko'rsatkichidan foydalanamiz.

Ob'ekt yaratilgan paytda, Student() konstruktori yoshni 12 ga ishga tushiradi.

Keyin kod yordamida get_age() funksiyasini chaqiramiz:

example.cpp
ptr->get_age();

-> o'q operatoriga e'tibor bering. Bu operator ko'rsatkichlar yordamida sinf a'zolariga kirish uchun ishlatiladi.

Nima uchun dinamik xotira ajratishdan foydalanish kerak?

Dinamik xotirani taqsimlash bir qator afzalliklarga ega, masalan:

  • Moslashuvchanlik: Dinamik xotira taqsimoti ish vaqtida kerak bo'lganda xotirani ajratish imkonini beradi. Ushbu moslashuvchanlik ma'lumotlar tuzilmalarining hajmi kompilyatsiya vaqtida ma'lum bo'lmaganda yoki dasturni bajarish paytida hajmi o'zgarganda foydalidir.

  • Ma'lumotlar tuzilmalari: Bog'langan ro'yxatlar, daraxtlar, grafiklar va o'lchamini o'zgartiruvchi massivlar (C++ da vektorlar) kabi ma'lumotlar tuzilmalari ko'pincha turli hajmdagi ma'lumotlarni joylashtirish uchun xotirani dinamik ravishda ajratishi kerak.

  • Resurslarni boshqarish: Biz xotirani kerak bo'lganda ajratishimiz va kerak bo'lmaganda uni ajratishimiz mumkin. Bu resurslardan yaxshiroq foydalanishga olib keladi.

  • Dinamik massivlar: C++ kabi tillarda statik massivlar kompilyatsiya vaqtida aniqlangan oʻlchamlarga ega. Dinamik xotira taqsimoti ish vaqtida hajmini aniqlash mumkin bo'lgan massivlarni yaratishga imkon beradi.

Ko'proq o'qish: