Sobes.tech
Middle+

Տարածման սեմանտիկայի ինչ է և ինչպես օգտագործել այն։

sobes.tech AI

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

Մշակման իմաստաբանությունը (move semantics) C++11-ից և ավելի բարձր տարբերակներում թույլ է տալիս արդյունավետ փոխանցել ռեսուրսի տիրապետությունը մեկ օբյեկտից մյուսին, խուսափելով անպատճառ կրկնօրինակումից: Սա հասնում է rvalue-ների ( && ) և move օպերատորի ( std::move ) օգտագործմամբ:

Հիմնական ասպեկտները:

  • rvalue-ներ (&&): Հղումներ ժամանակավոր օբյեկտներին կամ օբյեկտներին, որոնք նշված են որպես տեղափոխվող: Позволяют привязаться к объекту, который скоро будет уничтожен.
  • Տեղափոխման օպերատոր (std::move): Փոխում է lvalue-ներին rvalue-ների հղում: Ինքը չի իրականացնում տեղափոխում, այլ միայն ազդանշան է տալիս կոմպիլյատորին, որ օբյեկտը կարելի է անվտանգ տեղափոխել:
  • Տեղափոխման կոնստրուկտոր: Մասնակի կոնստրուկտոր, որը ընդունում է rvalue-ի հղում որպես արգումենտ: Այն "կլանում" ռեսուրսները (օրինակ, դինամիկ հիշողության ցուցիչներ) սկզբնական օբյեկտից, թողնելով այն վավեր, բայց դատարկ վիճակում:
  • Տեղափոխման վերագրում օպերատոր: Դեռևս կոնստրուկտորին նման, նախատեսված է վերագրումների համար:

Կիրառում:

  1. Օպտիմիզացիա: Կրճատում է մեծ օբյեկտների կամ ռեսուրսներ ունեցող օբյեկտների կրկնօրինակման ծախսերը (օրինակ, կոնտեյներներ, տողեր, խելացի ցուցիչներ):
  2. Արդյունավետ կոնտեյներների իրականացում: Позволяет контейнерам, כגון std::vector, արդյունավետ կառավարել տարրերը չափի փոփոխության կամ տեղափոխման ժամանակ:
  3. Մեծ օբյեկտների վերադարձը արժեքով: Կոմպիլյատորը կարող է ավտոմատ կերպով կիրառել տեղափոխում (return value optimization, RVO կամ Named Return Values Optimization, NRVO), եթե վերադարձվող օբյեկտը տեղական կամ ժամանակավոր օբյեկտ է:

Օրինակ:

#include <iostream>
#include <vector>
#include <string>
#include <utility> // `std::move` համար

class MyResource {
public:
    std::vector<int> data;

    // Կոնստրուկտոր
    MyResource(size_t size) : data(size) {
        std::cout << "Կոնստրուկտոր" << std::endl;
    }

    // Դեստրուկտոր
    ~MyResource() {
        std::cout << "Դեստրուկտոր" << std::endl;
    }

    // Կոնստրուկտոր կոպիայով
    MyResource(const MyResource& other) : data(other.data) {
        std::cout << "Կոնստրուկտոր կոպիայով" << std::endl;
    }

    // Վերագրում կոպիայով
    MyResource& operator=(const MyResource& other) {
        if (this != &other) {
            data = other.data;
        }
        std::cout << "Վերագրում օպերատոր կոպիայով" << std::endl;
        return *this;
    }

    // Տեղափոխման կոնստրուկտոր
    MyResource(MyResource&& other) noexcept : data(std::move(other.data)) {
        std::cout << "Տեղափոխման կոնստրուկտոր" << std::endl;
        // Թողնելով այն, սկզբնական օբյեկտը գտնվում է վավեր, բայց դատարկ վիճակում
        // other.data մնում է օրինական վեկտոր, բայց նրա պարունակությունը կարող է տեղափոխվել
    }

    // Տեղափոխման վերագրում օպերատոր
    MyResource& operator=(MyResource&& other) noexcept {
        if (this != &other) {
            data = std::move(other.data);
        }
        std::cout << "Տեղափոխման վերագրում օպերատոր" << std::endl;
        return *this;
    }
};

int main() {
    MyResource res1(10); // Կոնստրուկտոր
    std::cout << "---" << std::endl;
    MyResource res2 = res1; // Կոպիայով կոնստրուկտոր կամ վերագրում (եթե res2 արդեն գոյություն ունի)
    std::cout << "---" << std::endl;
    MyResource res3 = std::move(res1); // Տեղափոխման կոնստրուկտոր
    std::cout << "---" << std::endl;
    MyResource res4(5); // Կոնստրուկտոր
    res4 = std::move(res3); // Տեղափոխման վերագրում
    std::cout << "---" << std::endl;

    return 0;
}

Այս օրինակով նկատվում է, որ std::move-ի օգտագործմամբ կանչվում են տեղափոխման կոնստրուկտոր կամ տեղափոխման վերագրում, ինչը թույլ է տալիս խուսափել բարդ կրկնօրինակմանից, և արդյունավետորեն տեղափոխել data վեկտորի պարունակությունը։