在C++11及之后的标准中,结构体作为用户自定义类型,同样可以通过右值引用实现移动语义,从而在对象传递或返回时避免昂贵的深拷贝操作。对于包含动态资源的结构体,合理使用移动构造和移动赋值能显著提升性能。

什么是右值引用
右值引用使用T&&形式声明,专门用于绑定临时对象等右值。它能让我们识别出即将销毁的对象,从而安全地“窃取”其内部资源,而不是复制一份。
为结构体定义移动语义
假设我们有一个管理动态数组的结构体,下面通过移动构造函数和移动赋值运算符来支持移动语义。
#include <iostream>
#include <cstring>
struct Buffer {
char* data;
size_t size;
// 普通构造
Buffer(size_t n) : size(n) {
data = new char[n];
std::cout << "构造" << std::endl;
}
// 移动构造
Buffer(Buffer&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
std::cout << "移动构造" << std::endl;
}
// 移动赋值
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
std::cout << "移动赋值" << std::endl;
return *this;
}
~Buffer() {
delete[] data;
}
};
Buffer create() {
Buffer tmp(32);
return tmp; // 触发移动或复制消除
}
int main() {
Buffer a(10);
Buffer b = std::move(a); // 调用移动构造
Buffer c(5);
c = Buffer(20); // 调用移动赋值
return 0;
}
应用要点
- 移动操作后,源对象应处于可安全析构的状态,通常将指针置为nullptr。
- 移动构造和移动赋值建议标记为noexcept,以便标准库容器在扩容时优先使用移动而非拷贝。
- 使用
std::move可将左值转换为右值引用,从而触发移动语义。
小结
通过为结构体添加接受右值引用的移动构造与移动赋值,我们能让包含资源的自定义类型高效转移所有权。在实际项目中,这一做法对提升性能、降低内存开销有明显帮助。