Middle+
Տարածման սեմանտիկայի ինչ է և ինչպես օգտագործել այն։
sobes.tech AI
Պատասխան AI-ից
Մշակման իմաստաբանությունը (move semantics) C++11-ից և ավելի բարձր տարբերակներում թույլ է տալիս արդյունավետ փոխանցել ռեսուրսի տիրապետությունը մեկ օբյեկտից մյուսին, խուսափելով անպատճառ կրկնօրինակումից: Սա հասնում է rvalue-ների ( && ) և move օպերատորի ( std::move ) օգտագործմամբ:
Հիմնական ասպեկտները:
rvalue-ներ (&&): Հղումներ ժամանակավոր օբյեկտներին կամ օբյեկտներին, որոնք նշված են որպես տեղափոխվող: Позволяют привязаться к объекту, который скоро будет уничтожен.- Տեղափոխման օպերատոր (
std::move): Փոխում է lvalue-ներինrvalue-ների հղում: Ինքը չի իրականացնում տեղափոխում, այլ միայն ազդանշան է տալիս կոմպիլյատորին, որ օբյեկտը կարելի է անվտանգ տեղափոխել: - Տեղափոխման կոնստրուկտոր: Մասնակի կոնստրուկտոր, որը ընդունում է
rvalue-ի հղում որպես արգումենտ: Այն "կլանում" ռեսուրսները (օրինակ, դինամիկ հիշողության ցուցիչներ) սկզբնական օբյեկտից, թողնելով այն վավեր, բայց դատարկ վիճակում: - Տեղափոխման վերագրում օպերատոր: Դեռևս կոնստրուկտորին նման, նախատեսված է վերագրումների համար:
Կիրառում:
- Օպտիմիզացիա: Կրճատում է մեծ օբյեկտների կամ ռեսուրսներ ունեցող օբյեկտների կրկնօրինակման ծախսերը (օրինակ, կոնտեյներներ, տողեր, խելացի ցուցիչներ):
- Արդյունավետ կոնտեյներների իրականացում: Позволяет контейнерам, כגון
std::vector, արդյունավետ կառավարել տարրերը չափի փոփոխության կամ տեղափոխման ժամանակ: - Մեծ օբյեկտների վերադարձը արժեքով: Կոմպիլյատորը կարող է ավտոմատ կերպով կիրառել տեղափոխում (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 վեկտորի պարունակությունը։