适合谁看:资深的嵌入式系统底层专家。技能栈(C、SoC、Bootloader、驱动、系统移植、DSP优化、Cache调优、功耗分析)是芯片设计的核心和基础,具备从硬件(SoC) 到底层固件(ROM Bootloader)再到操作系统层(驱动、RTOS)的全栈知识和实战经验,希望向嵌入式场景的AI部署方向拓展,寻求新的发展空间。
现代C++提供移动语义支持,用以减少不必要的内存拷贝。早期版本的C++无法避免特定场景下的内存拷贝,现在引入了move操作,可以在无需拷贝实现移交资源的所有权移交。你在实现持有一些堆(heap memory)、文件句柄(file handles)这样的资源的类时,可以为它定义一个移动构造函数(move consturctor),供编译器在重载决议选用。
重载决议(Overload Resolution)是编译器在调用函数时,从多个候选函数中选择最匹配的函数的过程。在移动语义中,编译器优先选择移动构造函数或移动赋值运算符(如果可用),而不是拷贝操作
class X {
public:
X(); // 默认构造
X(const X&); // 拷贝构造
X(X&&); // 移动构造(右值引用)
};
X a;
X b = a; // 调用拷贝构造(a 是左值)
X c = X(); // 调用移动构造(X() 是右值)
如果 X 没有定义移动构造函数(即 X(X&&)),那么 X c = X();并不会调用移动构造,而是会回退到拷贝构造或直接优化掉拷贝。
当然了移动构造还是为了减少不必要的拷贝,像下面这样一个类:
class Buffer {
int* data; size_t size;
public:
Buffer(size_t size) : size(size), data(new int[size]) {}
~Buffer() {
delete[] data;
}
// 拷贝构造(深拷贝,成本高)
Buffer(const Buffer& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
}
// 移动构造(高效,直接“偷”资源)
Buffer(Buffer&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr; // 防止原对象析构时释放内存 other.size = 0;
}
};
用一个长度1024的vector初始化
std::vector<Buffer> vec;
vec.push_back(Buffer(1024));
如果没有移动构造,会调用拷贝构造(深拷贝 1024 个 int). 有移动构造就会调用移动构造,仅复制指针。
回想智能指针中的unique,禁止拷贝,只能移动所有权, 如果没有移动语义,unique_ptr就无法安全转移所有权
std::unique_ptr<int> p1 = std::make_unique<int>(42);
// std::unique_ptr<int> p2 = p1; // 错误!不能拷贝
std::unique_ptr<int> p2 = std::move(p1); // 正确,调用移动构造
什么时候需要移动构造?
| 场景 | 是否需要移动构造 |
|---|---|
std::vector/std::string扩容 | 必须(否则深拷贝) |
资源管理类(unique_ptr、文件句柄) | 必须(否则无法转移所有权) |
| 函数返回局部对象(RVO 可能失效) | 推荐(避免深拷贝) |
临时对象传递(如 X()) | 通常 RVO 优化掉,但移动构造 |