O'zbek

Zamonaviy C++ aqlli ko'rsatkichlarini (unique_ptr, shared_ptr, weak_ptr) mustahkam xotira boshqaruvi uchun o'rganing, xotira sizib chiqishining oldini oling va ilova barqarorligini oshiring. Eng yaxshi amaliyotlar va amaliy misollarni bilib oling.

C++ ning Zamonaviy Xususiyatlari: Samarali Xotira Boshqaruvi uchun Aqlli Ko'rsatkichlarni O'zlashtirish

Zamonaviy C++ da aqlli ko'rsatkichlar xotirani xavfsiz va samarali boshqarish uchun ajralmas vositalardir. Ular xotirani bo'shatish jarayonini avtomatlashtirib, an'anaviy C++ dasturlashida keng tarqalgan xotira sizib chiqishi va osilib qolgan ko'rsatkichlarning oldini oladi. Ushbu keng qamrovli qo'llanma C++ da mavjud bo'lgan aqlli ko'rsatkichlarning turli xillarini o'rganadi va ulardan samarali foydalanish bo'yicha amaliy misollarni taqdim etadi.

Aqlli Ko'rsatkichlarga bo'lgan Ehtiyojni Tushunish

Aqlli ko'rsatkichlarning o'ziga xos xususiyatlariga sho'ng'ishdan oldin, ular hal qiladigan muammolarni tushunish juda muhim. Klassik C++ da dasturchilar new va delete yordamida xotirani qo'lda ajratish va bo'shatish uchun mas'uldirlar. Bu qo'lda boshqaruv xatolarga moyil bo'lib, quyidagilarga olib keladi:

Bu muammolar dasturning ishdan chiqishiga, kutilmagan xatti-harakatlarga va xavfsizlik zaifliklariga olib kelishi mumkin. Aqlli ko'rsatkichlar dinamik ajratilgan obyektlarning yashash davrini avtomatik ravishda boshqarib, Resursni Olish - bu Initsializatsiya (RAII) tamoyiliga amal qilib, oqlangan yechim taklif qiladi.

RAII va Aqlli Ko'rsatkichlar: Kuchli Birikma

Aqlli ko'rsatkichlar ortidagi asosiy konsepsiya RAII bo'lib, u resurslarni obyekt yaratilishi paytida olinishi va obyekt yo'q qilinishi paytida bo'shatilishi kerakligini belgilaydi. Aqlli ko'rsatkichlar - bu oddiy ko'rsatkichni o'z ichiga olgan va aqlli ko'rsatkich amal qilish doirasidan chiqqanda ko'rsatilgan obyektni avtomatik ravishda o'chiradigan sinflardir. Bu hatto istisnolar mavjud bo'lganda ham xotiraning doimo bo'shatilishini ta'minlaydi.

C++ dagi Aqlli Ko'rsatkichlarning Turlari

C++ aqlli ko'rsatkichlarning uchta asosiy turini taqdim etadi, ularning har biri o'ziga xos xususiyatlarga va qo'llanilish holatlariga ega:

std::unique_ptr: Yagona Egalik

std::unique_ptr dinamik ravishda ajratilgan obyektga yagona egalikni ifodalaydi. Istalgan vaqtda faqat bitta unique_ptr ma'lum bir obyektga ishora qilishi mumkin. unique_ptr amal qilish doirasidan chiqqanda, u boshqaradigan obyekt avtomatik ravishda o'chiriladi. Bu unique_ptrni obyektning yashash davri uchun yagona subyekt mas'ul bo'lishi kerak bo'lgan holatlar uchun ideal qiladi.

Misol: std::unique_ptr dan foydalanish


#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int value) : value_(value) {
        std::cout << "MyClass qiymat bilan yaratildi: " << value_ << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass qiymat bilan yo'q qilindi: " << value_ << std::endl;
    }

    int getValue() const { return value_; }

private:
    int value_;
};

int main() {
    std::unique_ptr<MyClass> ptr(new MyClass(10)); // unique_ptr yaratish

    if (ptr) { // Ko'rsatkichning yaroqliligini tekshirish
        std::cout << "Qiymat: " << ptr->getValue() << std::endl;
    }

    // ptr amal qilish doirasidan chiqqanda, MyClass obyekti avtomatik ravishda o'chiriladi
    return 0;
}

std::unique_ptr ning Asosiy Xususiyatlari:

Misol: std::unique_ptr bilan std::move dan foydalanish


#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> ptr1(new int(42));
    std::unique_ptr<int> ptr2 = std::move(ptr1); // Egalikni ptr2 ga o'tkazish

    if (ptr1) {
        std::cout << "ptr1 hali ham yaroqli" << std::endl; // Bu bajarilmaydi
    } else {
        std::cout << "ptr1 endi null" << std::endl; // Bu bajariladi
    }

    if (ptr2) {
        std::cout << "ptr2 tomonidan ko'rsatilgan qiymat: " << *ptr2 << std::endl; // Natija: ptr2 tomonidan ko'rsatilgan qiymat: 42
    }

    return 0;
}

Misol: std::unique_ptr bilan Maxsus O'chiruvchilardan foydalanish


#include <iostream>
#include <memory>

// Fayl identifikatorlari uchun maxsus o'chiruvchi
struct FileDeleter {
    void operator()(FILE* file) const {
        if (file) {
            fclose(file);
            std::cout << "Fayl yopildi." << std::endl;
        }
    }
};

int main() {
    // Faylni ochish
    FILE* file = fopen("example.txt", "w");
    if (!file) {
        std::cerr << "Faylni ochishda xatolik." << std::endl;
        return 1;
    }

    // Maxsus o'chiruvchi bilan unique_ptr yaratish
    std::unique_ptr<FILE, FileDeleter> filePtr(file);

    // Faylga yozish (ixtiyoriy)
    fprintf(filePtr.get(), "Salom, dunyo!\n");

    // filePtr amal qilish doirasidan chiqqanda, fayl avtomatik ravishda yopiladi
    return 0;
}

std::shared_ptr: Umumiy Egalik

std::shared_ptr dinamik ravishda ajratilgan obyektga umumiy egalikni ta'minlaydi. Bir nechta shared_ptr nusxalari bir xil obyektga ishora qilishi mumkin va obyekt faqat unga ishora qiluvchi oxirgi shared_ptr amal qilish doirasidan chiqqanda o'chiriladi. Bunga havola sanash orqali erishiladi, bunda har bir shared_ptr yaratilganda yoki nusxalanganda hisobni oshiradi va yo'q qilinganda hisobni kamaytiradi.

Misol: std::shared_ptr dan foydalanish


#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1(new int(100));
    std::cout << "Havolalar soni: " << ptr1.use_count() << std::endl; // Natija: Havolalar soni: 1

    std::shared_ptr<int> ptr2 = ptr1; // shared_ptr nusxasini olish
    std::cout << "Havolalar soni: " << ptr1.use_count() << std::endl; // Natija: Havolalar soni: 2
    std::cout << "Havolalar soni: " << ptr2.use_count() << std::endl; // Natija: Havolalar soni: 2

    {
        std::shared_ptr<int> ptr3 = ptr1; // Amal qilish doirasi ichida shared_ptr nusxasini olish
        std::cout << "Havolalar soni: " << ptr1.use_count() << std::endl; // Natija: Havolalar soni: 3
    } // ptr3 amal qilish doirasidan chiqadi, havolalar soni kamayadi

    std::cout << "Havolalar soni: " << ptr1.use_count() << std::endl; // Natija: Havolalar soni: 2

    ptr1.reset(); // Egalikdan voz kechish
    std::cout << "Havolalar soni: " << ptr2.use_count() << std::endl; // Natija: Havolalar soni: 1

    ptr2.reset(); // Egalikdan voz kechish, obyekt endi o'chiriladi

    return 0;
}

std::shared_ptr ning Asosiy Xususiyatlari:

std::shared_ptr uchun Muhim Fikrlar:

std::weak_ptr: Egalik qilmaydigan Kuzatuvchi

std::weak_ptr shared_ptr tomonidan boshqariladigan obyektga egalik qilmaydigan havola beradi. U havola sanash mexanizmida ishtirok etmaydi, ya'ni barcha shared_ptr nusxalari amal qilish doirasidan chiqqanda obyektning o'chirilishiga to'sqinlik qilmaydi. weak_ptr obyektga egalik qilmasdan uni kuzatish uchun, ayniqsa tsiklik bog'liqliklarni buzish uchun foydalidir.

Misol: Tsiklik Bog'liqliklarni Buzish uchun std::weak_ptr dan foydalanish


#include <iostream>
#include <memory>

class B;

class A {
public:
    std::shared_ptr<B> b;
    ~A() { std::cout << "A yo'q qilindi" << std::endl; }
};

class B {
public:
    std::weak_ptr<A> a; // Tsiklik bog'liqlikning oldini olish uchun weak_ptr dan foydalanish
    ~B() { std::cout << "B yo'q qilindi" << std::endl; }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->b = b;
    b->a = a;

    // weak_ptr bo'lmaganda, A va B tsiklik bog'liqlik tufayli hech qachon yo'q qilinmas edi
    return 0;
} // A va B to'g'ri yo'q qilinadi

Misol: Obyekt Yaroqliligini Tekshirish uchun std::weak_ptr dan foydalanish


#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(123);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // Obyekt hali ham mavjudligini tekshirish
    if (auto observedPtr = weakPtr.lock()) { // lock() obyekt mavjud bo'lsa, shared_ptr qaytaradi
        std::cout << "Obyekt mavjud: " << *observedPtr << std::endl; // Natija: Obyekt mavjud: 123
    }

    sharedPtr.reset(); // Egalikdan voz kechish

    // sharedPtr tiklangandan keyin yana tekshirish
    if (auto observedPtr = weakPtr.lock()) {
        std::cout << "Obyekt mavjud: " << *observedPtr << std::endl; // Bu bajarilmaydi
    } else {
        std::cout << "Obyekt yo'q qilingan." << std::endl; // Natija: Obyekt yo'q qilingan.
    }

    return 0;
}

std::weak_ptr ning Asosiy Xususiyatlari:

To'g'ri Aqlli Ko'rsatkichni Tanlash

Tegishli aqlli ko'rsatkichni tanlash siz tatbiq etishingiz kerak bo'lgan egalik semantikasiga bog'liq:

Aqlli Ko'rsatkichlardan Foydalanish bo'yicha Eng Yaxshi Amaliyotlar

Aqlli ko'rsatkichlarning afzalliklarini maksimal darajada oshirish va keng tarqalgan xatolardan qochish uchun quyidagi eng yaxshi amaliyotlarga rioya qiling:

Misol: std::make_unique va std::make_shared dan foydalanish


#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int value) : value_(value) {
        std::cout << "MyClass qiymat bilan yaratildi: " << value_ << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass qiymat bilan yo'q qilindi: " << value_ << std::endl;
    }

    int getValue() const { return value_; }

private:
    int value_;
};

int main() {
    // std::make_unique dan foydalanish
    std::unique_ptr<MyClass> uniquePtr = std::make_unique<MyClass>(50);
    std::cout << "Unique pointer qiymati: " << uniquePtr->getValue() << std::endl;

    // std::make_shared dan foydalanish
    std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(100);
    std::cout << "Shared pointer qiymati: " << sharedPtr->getValue() << std::endl;

    return 0;
}

Aqlli Ko'rsatkichlar va Istisnolar Xavfsizligi

Aqlli ko'rsatkichlar istisnolar xavfsizligiga sezilarli hissa qo'shadi. Dinamik ajratilgan obyektlarning yashash davrini avtomatik ravishda boshqarish orqali, ular istisno yuzaga kelgan taqdirda ham xotiraning bo'shatilishini ta'minlaydi. Bu xotira sizib chiqishining oldini oladi va ilovangizning yaxlitligini saqlashga yordam beradi.

Oddiy ko'rsatkichlardan foydalanganda xotiraning sizib chiqishi mumkin bo'lgan quyidagi misolni ko'rib chiqing:


#include <iostream>

void processData() {
    int* data = new int[100]; // Xotira ajratish

    // Istisno keltirib chiqarishi mumkin bo'lgan ba'zi operatsiyalarni bajarish
    try {
        // ... potentsial istisno keltirib chiqaruvchi kod ...
        throw std::runtime_error("Nimadir noto'g'ri ketdi!"); // Misol istisno
    } catch (...) {
        delete[] data; // catch blokida xotirani bo'shatish
        throw; // Istisnoni qayta yuborish
    }

    delete[] data; // Xotirani bo'shatish (faqat istisno yuzaga kelmasa erishiladi)
}

Agar try bloki ichida birinchi delete[] data; iborasidan *oldin* istisno yuzaga kelsa, data uchun ajratilgan xotira sizib chiqadi. Aqlli ko'rsatkichlardan foydalanib, buning oldini olish mumkin:


#include <iostream>
#include <memory>

void processData() {
    std::unique_ptr<int[]> data(new int[100]); // Aqlli ko'rsatkich yordamida xotira ajratish

    // Istisno keltirib chiqarishi mumkin bo'lgan ba'zi operatsiyalarni bajarish
    try {
        // ... potentsial istisno keltirib chiqaruvchi kod ...
        throw std::runtime_error("Nimadir noto'g'ri ketdi!"); // Misol istisno
    } catch (...) {
        throw; // Istisnoni qayta yuborish
    }

    // data'ni aniq o'chirishga hojat yo'q; unique_ptr buni avtomatik ravishda bajaradi
}

Ushbu yaxshilangan misolda, unique_ptr data uchun ajratilgan xotirani avtomatik ravishda boshqaradi. Agar istisno yuzaga kelsa, stek ochilishi paytida unique_ptr ning destruktori chaqiriladi, bu esa istisno ushlanishi yoki qayta yuborilishidan qat'i nazar, xotiraning bo'shatilishini ta'minlaydi.

Xulosa

Aqlli ko'rsatkichlar xavfsiz, samarali va qo'llab-quvvatlanadigan C++ kodini yozish uchun asosiy vositalardir. Xotira boshqaruvini avtomatlashtirish va RAII tamoyiliga rioya qilish orqali, ular oddiy ko'rsatkichlar bilan bog'liq keng tarqalgan muammolarni bartaraf etadi va yanada mustahkam ilovalarga hissa qo'shadi. Aqlli ko'rsatkichlarning har xil turlarini va ularning tegishli qo'llanilish holatlarini tushunish har bir C++ dasturchisi uchun zarurdir. Aqlli ko'rsatkichlarni o'zlashtirish va eng yaxshi amaliyotlarga rioya qilish orqali siz xotira sizib chiqishini, osilib qolgan ko'rsatkichlarni va boshqa xotira bilan bog'liq xatolarni sezilarli darajada kamaytirishingiz mumkin, bu esa yanada ishonchli va xavfsiz dasturiy ta'minotga olib keladi.

Silikon Vodiysida yuqori unumdorlikdagi hisoblashlar uchun zamonaviy C++ dan foydalanayotgan startaplardan tortib, muhim tizimlarni ishlab chiquvchi global korxonalargacha, aqlli ko'rsatkichlar universal qo'llaniladi. Siz Buyumlar Interneti uchun o'rnatilgan tizimlarni qurayotgan bo'lasizmi yoki ilg'or moliyaviy ilovalarni ishlab chiqayotgan bo'lasizmi, aqlli ko'rsatkichlarni o'zlashtirish mukammallikka intilayotgan har qanday C++ dasturchisi uchun asosiy mahoratdir.

Qo'shimcha O'rganish uchun