Sobes.tech
Middle

Ինչպես է աշխատում հղումների հաշվիչը std::shared_ptr-ում։

sobes.tech AI

Պատասխան AI-ից

std::shared_ptr-ի հղումների հաշվիչը պահվում է առանձին օբյեկտում՝ կառավարման բլոկում (control block):

Կառավարման բլոկը ստեղծվում է՝

  • Երբ առաջին անգամ std::shared_ptr-ը ստեղծվում է ցուցիչից:
  • Երբ std::shared_ptr-ը ստեղծվում է օգտագործողի կողմից սահմանված մաքրման գործառական կամ ալոկատորով:
  • Երբ օգտագործվում է std::make_shared կամ std::allocate_shared:

Այս կառավարման բլոկը պարունակում է առնվազն երկու հաշվիչ՝

  1. Համառկած հղումների հաշվիչ (strong count): Հավելվում է std::shared_ptr-ի ստեղծման կամ պատճենահանման ժամանակ, նվազում՝ այն ոչնչացնելիս: Երբ այս հաշվիչը դառնում է զրո, կառավարելի օբյեկտը ազատվում է:
  2. Ազատ հղումների հաշվիչ (weak count): Հավելվում է std::weak_ptr-ի ստեղծման ժամանակ, նվազում՝ այն ոչնչացնելիս: Կառավարման բլոկը ազատվում է, երբ երկու հաշվիչներն էլ՝ ուժեղ և թույլ, դառնում են զրո:

std::make_shared-ի օգտագործումը նախընտրելի է ուղղակի new-ից ստեղծելու փոխարեն, քանի որ այն կարող է միաժամանակ ալոկատել օբյեկտը և կառավարման բլոկը՝ մեկ հիշողության բլոկում, ինչը բարելավում է կատարողականությունը և նվազեցնում ֆրագմենտացիան:

Ատոմիկ հաշվիչները ապահովում են std::shared_ptr-ի անվտանգությունը բազմաթ/thread-ային միջավայրում, չնայած կառավարվող օբյեկտի մուտք գործելը ըստ նախնական կարգավորումների չի սինխրոնիզացված:

Օրինակ՝

#include <iostream>
#include <memory>

struct MyObject {
    int data;
    MyObject(int d) : data(d) {
        std::cout << "MyObject(" << data << ") ստեղծվեց\n";
    }
    ~MyObject() {
        std::cout << "MyObject(" << data << ") ոչնչացվեց\n";
    }
};

int main() {
    std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
    // ուժեղ հաշվիչ: 1, թույլ հաշվիչ: 0

    {
        std::shared_ptr<MyObject> ptr2 = ptr1;
        // ուժեղ հաշվիչ: 2, թույլ հաշվիչ: 0

        std::weak_ptr<MyObject> weak_ptr = ptr1;
        // ուժեղ հաշվիչ: 2, թույլ հաշվիչ: 1

        if (auto locked_ptr = weak_ptr.lock()) {
            // ուժեղ հաշվիչ: 3, թույլ հաշվիչ: 1 (lock-ի ներսում)
            std::cout << "Объект տվյալները: " << locked_ptr->data << std::endl;
        }
        // ուժեղ հաշվիչ: 2, թույլ հաշվիչ: 1
    } // ptr2 դուրս է գալիս տարածքից
    // ուժեղ հաշվիչ: 1, թույլ հաշվիչ: 1

    // Օբյեկտը դեռ չի ոչնչացվել, քանի որ ուժեղ հաշվիչը == 1

    {
        std::weak_ptr<MyObject> weak_ptr2 = ptr1;
        // ուժեղ հաշվիչ: 1, թույլ հաշվիչ: 2
    } // weak_ptr2 դուրս է գալիս տարածքից
    // ուժեղ հաշվիչ: 1, թույլ հաշվիչ: 1

} // ptr1 դուրս է գալիս տարածքից
// ուժեղ հաշվիչ: 0, թույլ հաշվիչ: 1
// Օբյեկտը ոչնչացվում է, քանի որ ուժեղ հաշվիչը դարձել է 0
// Կառավարման բլոկը մնում է մինչև թույլ հաշվիչը չդառնա 0