C++ Move Semantics
Move semantics let C++ transfer resources from one object to another instead of copying them. This is especially useful for objects that own memory, files, strings, vectors, or smart pointers.
A move can be much cheaper than a copy because the new object can take over an existing resource. The original object is left valid, but its exact value should usually not be relied on.
Copying Versus Moving
A copy creates a second independent value. For example, copying a large std::vector may require allocating new memory and copying every element.
A move transfers ownership of the existing internal resource when possible. Many standard library types, including std::string, std::vector, and std::unique_ptr, support moving.
lvalues and rvalues
An lvalue is an object with a name or stable location, such as a variable. An rvalue is a temporary value, such as the result of an expression or a value that is about to be discarded.
Move operations are normally selected for rvalues. To say that a named object may be treated like an rvalue, use std::move from the <utility> header.
Using std::move
std::move does not move anything by itself. It casts its argument so C++ is allowed to call a move constructor or move assignment operator if one is available.
#include <iostream>
#include <string>
#include <utility>
int main(void) {
std::string first = "C++ course";
std::string second = std::move(first);
std::cout << "second: " << second << std::endl;
first = "new text";
std::cout << "first: " << first << std::endl;
return 0;
}
Output:
second: C++ course
first: new text
After std::move(first), second receives the string value. The moved-from first is still a valid string, so it can be assigned a new value. The example does not read the old contents of first after the move, because that value is not something portable code should depend on.
Move Constructors
A class that owns a resource can define a move constructor. The move constructor takes an rvalue reference, written with &&, and transfers the resource from the source object.
#include <iostream>
#include <utility>
class Buffer {
private:
int* data;
int size;
public:
Buffer(int count) {
size = count;
data = new int[size];
std::cout << "create buffer" << std::endl;
}
~Buffer() {
delete[] data;
}
Buffer(const Buffer& other) {
size = other.size;
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
std::cout << "copy buffer" << std::endl;
}
Buffer(Buffer&& other) noexcept {
size = other.size;
data = other.data;
other.size = 0;
other.data = nullptr;
std::cout << "move buffer" << std::endl;
}
int length(void) const {
return size;
}
};
int main(void) {
Buffer a(5);
Buffer b = a;
Buffer c = std::move(a);
std::cout << "b length: " << b.length() << std::endl;
std::cout << "c length: " << c.length() << std::endl;
std::cout << "a length: " << a.length() << std::endl;
return 0;
}
Output:
create buffer
copy buffer
move buffer
b length: 5
c length: 5
a length: 0
The copy constructor allocates a new array and copies each element. The move constructor simply copies the pointer and size, then resets the old object so its destructor will not delete the same array twice.
Moved-From Objects
A moved-from object must be safe to destroy and safe to assign a new value. However, unless a type documents something more specific, you should not depend on the old value after a move.
- It is fine to destroy a moved-from object.
- It is fine to assign a new value to a moved-from object.
- It is usually not a good idea to read its old contents.
When to Use Move Semantics
- Use
std::movewhen you are done with a named object and want another object to take its resources. - Do not use
std::moveon an object you still need to read normally. - Mark custom move constructors and move assignment operators
noexceptwhen they cannot throw. - Prefer standard library types when possible; they already implement efficient move behavior.
Takeaway: move semantics let C++ transfer ownership efficiently, but after moving from an object, only destroy it, assign to it, or use operations that are documented to be safe.
