背景
在 C++ 中,move-only 类型(move-only type)是指那些不能被复制(copy),只能通过移动(move)来传递的类型。这些类型通常会禁用拷贝构造函数和拷贝赋值运算符,并且提供移动构造函数和移动赋值运算符。
常用
- std::unique_ptr
std::unique_ptr 是 C++11 引入的智能指针,它表示对动态分配内存的唯一所有权。它只能被移动,不能被拷贝。
这意味着你不能通过拷贝构造或拷贝赋值来共享内存资源,只有通过移动操作来转移所有权。
std::unique_ptr<int> p1 = std::make_unique<int>(10);
std::unique_ptr<int> p2 = std::move(p1); // p1 被清空,p2 现在拥有资源
- std::mutex
std::mutex 是 C++11 引入的用于线程同步的对象。它表示对互斥锁的唯一所有权,不能被拷贝或赋值。
它是 move-only 类型,因为多个线程共享同一个互斥锁对象会导致同步问题,所以不能拷贝。
std::mutex mtx1;
std::mutex mtx2 = std::move(mtx1); // 可以通过移动来转移所有权,但不能拷贝
- std::unique_lock
std::unique_lock 是 std::mutex 的一个封装,提供了更灵活的锁管理功能。它是 move-only 类型,因为它持有的锁对象不能被拷贝,只能被移动。
std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2 = std::move(lock1); // lock1 失效,lock2 现在拥有锁
- std::thread
std::thread 表示一个可以执行任务的线程对象。线程对象是 move-only 类型,因为一个线程只能拥有一次执行,不能在多个对象间拷贝。
在创建线程时,你不能拷贝线程对象,只能通过移动来传递所有权。
std::thread t1([](){ /* do something */ });
std::thread t2 = std::move(t1); // 移动线程
- std::promise 和 std::future
std::promise 和 std::future 用于线程间通信,尤其是在异步操作中传递结果。std::promise 是 move-only 类型,因为它代表一个承诺的结果,不能被复制。
std::future 也是 move-only 类型,因为它表示未来某个时刻的结果,只能通过移动来获取。
std::promise<int> p;
std::future<int> f = p.get_future();
std::future<int> f2 = std::move(f); // 移动 future,f 不再有效
- std::aligned_storage
std::aligned_storage 是 C++ 标准库中的一个模板类,用于表示具有特定对齐要求的未初始化存储。虽然它本身并不是完全 move-only 类型,但在某些应用中,存储的对象可能是 move-only 类型,例如通过 std::aligned_storage 进行内存管理的类型。 - 自定义的 Move-Only 类型
在一些情况下,你可能会自定义自己的 move-only 类型。这些类型通常会禁用拷贝构造函数和拷贝赋值运算符,并提供移动构造函数和移动赋值运算符。例如,表示文件句柄、网络连接等资源的类常常是 move-only 类型。
class MoveOnly {
public:
MoveOnly() = default;
MoveOnly(const MoveOnly&) = delete; // 禁止拷贝构造
MoveOnly& operator=(const MoveOnly&) = delete; // 禁止拷贝赋值
MoveOnly(MoveOnly&&) = default; // 允许移动构造
MoveOnly& operator=(MoveOnly&&) = default; // 允许移动赋值
};