Middle+
გადადგილების სემანტიკა რა არის და როგორ გამოიყენება?
sobes.tech AI
პასუხი AI-სგან
move semantics (მოძრაობის მნიშვნელობა) C++11-დან და ზევით ვერსიებში საშუალებას აძლევს ეფექტურად გადმოსცეს რესურსის მფლობელობა ერთ ობიექტიდან მეორეზე, თავიდან აიცილოს საჭირო გამეორებითი კოპირება. ეს მიღწეულია rvalue-ების (&&) და 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;
// საწყის ობიექტი რჩება ვალიდური, მაგრამ ცარიელი
}
// გადატანის მიანიჭების ოპერატორი
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; // კოპირების კონსტრუქტორი
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 ვექტორის შიგთავსი და თავიდან აიცილოს ძვირი ხარჯი მისი კოპირებისას.