C++ Move Constructor: rvalue Stealing & noexcept Best Practices
이 글의 핵심
Practical guide to move constructors: stealing from rvalues, interaction with noexcept and containers, and common pitfalls.
What is a move constructor?
A constructor that transfers resources from an rvalue.
class Buffer {
int* data;
size_t size;
public:
// Move constructor
Buffer(Buffer&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
};
Copy vs move
// Copy: duplicate resources
Buffer(const Buffer& other) {
data = new int[other.size];
std::copy(other.data, other.data + size, data);
}
// Move: transfer ownership
Buffer(Buffer&& other) noexcept {
data = other.data;
other.data = nullptr;
}
Practical examples
Example 1: Basic implementation
class String {
char* data;
size_t length;
public:
String(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
~String() {
delete[] data;
}
// Copy constructor
String(const String& other) : length(other.length) {
data = new char[length + 1];
strcpy(data, other.data);
std::cout << "copy" << std::endl;
}
// Move constructor
String(String&& other) noexcept
: data(other.data), length(other.length) {
other.data = nullptr;
other.length = 0;
std::cout << "move" << std::endl;
}
};
int main() {
String s1("Hello");
String s2 = s1; // copy
String s3 = std::move(s1); // move
}
Example 2: Vector behavior
#include <vector>
class Widget {
public:
Widget() { std::cout << "ctor" << std::endl; }
Widget(const Widget&) { std::cout << "copy" << std::endl; }
Widget(Widget&&) noexcept { std::cout << "move" << std::endl; }
};
int main() {
std::vector<Widget> vec;
vec.reserve(10);
Widget w;
vec.push_back(w); // copy
vec.push_back(std::move(w)); // move
vec.emplace_back(); // construct in place
}
Example 3: Smart pointers
#include <memory>
class Resource {
public:
Resource() { std::cout << "Resource ctor" << std::endl; }
~Resource() { std::cout << "Resource dtor" << std::endl; }
};
int main() {
auto ptr1 = std::make_unique<Resource>();
// Move only (no copy)
auto ptr2 = std::move(ptr1);
// ptr1 is nullptr
}
Example 4: Return value optimization
Buffer createBuffer(size_t size) {
Buffer b(size);
return b; // move or RVO
}
int main() {
Buffer b = createBuffer(100);
}
Why noexcept matters
// Without noexcept: vector may fall back to copy on reallocation
Buffer(Buffer&& other) {
// ...
}
// With noexcept: vector can move elements
Buffer(Buffer&& other) noexcept {
// ...
}
Common pitfalls
Pitfall 1: State after move
// Bad: moved-from not cleared
Buffer(Buffer&& other) noexcept {
data = other.data;
// other.data still non-null (risky)
}
// Good: null out source
Buffer(Buffer&& other) noexcept {
data = other.data;
other.data = nullptr;
}
Pitfall 2: Self-move
// Bad: no self-check
Buffer& operator=(Buffer&& other) noexcept {
delete[] data;
data = other.data;
other.data = nullptr;
return *this;
}
// Good: guard self-assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
other.data = nullptr;
}
return *this;
}
Pitfall 3: Exception safety
// May throw
Buffer(Buffer&& other) {
// ...
}
// noexcept when possible
Buffer(Buffer&& other) noexcept {
// ...
}
Pitfall 4: std::move on return locals
// Bad: can block NRVO
Buffer func() {
Buffer b(100);
return std::move(b);
}
// Good: just return
Buffer func() {
Buffer b(100);
return b;
}
Types that move
// Move-capable
std::vector<int>
std::string
std::unique_ptr<int>
// No move (trivially copyable scalars)
int
double
FAQ
Q1: When is the move ctor used?
A: When constructing from an rvalue (including moved lvalues).
Q2: Is noexcept mandatory?
A:
- Not required by the language
- Important for
std::vectorand strong guarantees
Q3: Valid state after move?
A: Object must be valid but unspecified; nulling pointers is good practice.
Q4: What is std::move?
A: Cast to rvalue reference; does not move by itself.
Q5: Performance?
A: Pointer swaps instead of deep copies—big win for large objects.
Q6: Resources?
A:
- Effective Modern C++
- C++ Move Semantics (general references)
- cppreference.com
Related posts (internal links)
- noexcept specifier
- Rule of Five
- Exception performance
Practical tips
Debugging
- Warnings first, minimal repro
Performance
- Measure before tuning
Code review
- Team conventions
Practical checklist
Before coding
- Right tool for the job?
- Maintainable?
- Performance OK?
While coding
- Warnings fixed?
- Edge cases?
- Errors handled?
At review
- Clear intent?
- Tests?
- Docs?
Keywords
C++, move constructor, move semantics, C++11, performance
Related posts
- Algorithm sort
- async & launch
- Atomic operations
- Attributes
- auto keyword