在 C++ 中,智能指针(如 std::unique_ptr 和 std::shared_ptr)通过 RAII 自动管理资源。若要自定义智能指针,必须正确实现移动语义,以保证资源的唯一所有权能够安全转移。下面给出一个最小可行的示例,并说明关键点。
-
定义类骨架
template<typename T> class MyUniquePtr { T* ptr_; public: explicit MyUniquePtr(T* p = nullptr) noexcept : ptr_(p) {} ~MyUniquePtr() { delete ptr_; } // 禁止拷贝 MyUniquePtr(const MyUniquePtr&) = delete; MyUniquePtr& operator=(const MyUniquePtr&) = delete; }; -
实现移动构造函数
MyUniquePtr(MyUniquePtr&& other) noexcept : ptr_(other.ptr_) { // 直接转移指针 other.ptr_ = nullptr; // 源对象释放时不再删除 } -
实现移动赋值运算符
MyUniquePtr& operator=(MyUniquePtr&& other) noexcept { if (this != &other) { delete ptr_; // 先释放当前资源 ptr_ = other.ptr_; // 再转移新资源 other.ptr_ = nullptr; // 让源对象为空 } return *this; } -
提供成员访问
T& operator*() const { return *ptr_; } T* operator->() const noexcept { return ptr_; } T* get() const noexcept { return ptr_; } -
测试
struct Demo { int val; }; int main() { MyUniquePtr <Demo> p1(new Demo{10}); MyUniquePtr <Demo> p2 = std::move(p1); // 移动构造 std::cout << p2->val << std::endl; // 输出 10 // p1 现在为空,尝试访问会导致空指针异常 }
关键点回顾
- 禁止拷贝:通过
delete拷贝构造函数和拷贝赋值运算符,确保资源所有权唯一。 - 移动构造函数:直接转移指针并将源对象置为空,使用
noexcept标记以满足标准库容器对移动构造函数的异常安全要求。 - 移动赋值运算符:先释放自身已有资源,再转移指针;注意自我赋值时的保护。
- 异常安全:在移动构造中不需要处理异常;移动赋值中若
delete失败(不可能),则保持原始对象不变。 - 接口:提供
operator*,operator->,get()等常见接口,以兼容标准库习惯。
通过上述实现,你可以拥有一个既安全又符合现代 C++ 风格的自定义智能指针,既可在容器中使用,又可满足多态场景下的灵活性需求。