move semantics (tsz. move semanticses)
Hagyományos másolás során az objektum összes erőforrását (pl. heap-en lévő memóriaterület) lemásoljuk. Ez költséges lehet:
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = v1; // másolat, az elemek is másolódnak
C++98-ben ez volt az egyetlen lehetőség. De mi van akkor, ha v1
-et már nem akarjuk használni? Ekkor jön képbe a move konstruktor és move értékadó operátor.
a
, vec
, obj
)5
, a + b
, std::string("abc")
)int a = 5; // a: lvalue, 5: rvalue
std::string s = std::string("hello"); // jobb oldali std::string: rvalue
std::move
A std::move()
egy cast, amely egy lvalue-t rvalue-re castol, így mozgathatóvá válik.
std::string a = "alma";
std::string b = std::move(a); // b "ellopja" a tartalmát
Ez nem másolás, hanem áthelyezés. a
érvényes, de meg nem határozott állapotban van.
class MyClass {
int* data;
size_t size;
public:
// Move konstruktor
MyClass(MyClass&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// Move értékadó operátor
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
delete data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
// Destruktor
~MyClass() {
delete data;
}
// Konstruktor
MyClass(size_t s) : data(new int), size(s) {}
};
MyClass a(1000); // nagy tömb
MyClass b = std::move(a); // nem másolat, hanem move!
a
többé nem birtokolja az erőforrást, b
viszont igen. Ez sokkal gyorsabb, mintha az egész data
tartalom másolva lenne.
std::vector<int> create_vector() {
std::vector<int> vec = {1, 2, 3, 4};
return vec; // C++11-től ez mozgás (return value optimization - RVO)
}
std::vector<std::string> v;
std::string name = "ChatGPT";
v.push_back(std::move(name)); // nem másol, hanem move-ol
Ha egy osztály:
Akkor implementálni kell:
class MyClass {
// rule of five megvalósítás itt
};
Az STL konténerek (pl. std::vector
, std::map
) teljes mértékben támogatják a move szemantikát. Ha az elemek move-képesek, akkor a konténerek is gyorsabbak lesznek.
std::vector<std::string> v;
v.push_back(std::move(myStr)); // move konstruktor hívódik meg
std::is_move_constructible
#include <type_traits>
std::is_move_constructible<MyClass>::value; // true vagy false
Ez megmondja, hogy egy típus mozgatható-e.
Olyan osztály, amely csak mozgatható, de nem másolható:
class Unique {
std::unique_ptr<int> ptr;
public:
Unique(std::unique_ptr<int> p) : ptr(std::move(p)) {}
Unique(const Unique&) = delete;
Unique& operator=(const Unique&) = delete;
Unique(Unique&&) = default;
Unique& operator=(Unique&&) = default;
};
Ilyen pl. std::unique_ptr
maga is.
Fogalom | Jelentés |
---|---|
std::move
|
Lvalue-t rvalue-vé alakít |
Move konstruktor | Erőforrásokat „ellopó” konstruktor |
Move értékadó operátor | Mozgatás értékadáskor |
RVO / NRVO | Return Value Optimization (másolás elkerülése) |
Rule of Five | 5 alapvető metódus, ha erőforrásokat kezelünk |
Move-only típus | Nem másolható, csak mozgatható objektum |