1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #ifndef SMART_PTR_H #define SMART_PTR_H
// 基于RAII的智能指针实现,模拟unique_ptr template <typename T> class SmartPtr { private: T* m_ptr; // 指向管理的资源
public: // 构造函数:获取资源 explicit SmartPtr(T* ptr = nullptr) : m_ptr(ptr) {}
// 析构函数:释放资源(RAII核心) ~SmartPtr() { delete m_ptr; // 自动释放资源 m_ptr = nullptr; }
// 禁止复制构造和复制赋值(确保独占所有权) SmartPtr(const SmartPtr& other) = delete; SmartPtr& operator=(const SmartPtr& other) = delete;
// 允许移动构造和移动赋值(所有权转移) SmartPtr(SmartPtr&& other) noexcept : m_ptr(other.m_ptr) { other.m_ptr = nullptr; // 源对象不再拥有资源 }
SmartPtr& operator=(SmartPtr&& other) noexcept { if (this != &other) { delete m_ptr; // 释放当前资源 m_ptr = other.m_ptr; // 转移所有权 other.m_ptr = nullptr; // 源对象不再拥有资源 } return *this; }
// 指针操作符重载 T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
// 获取原始指针 T* get() const { return m_ptr; }
// 释放资源所有权 T* release() { T* temp = m_ptr; m_ptr = nullptr; return temp; }
// 重置资源 void reset(T* ptr = nullptr) { if (m_ptr != ptr) { delete m_ptr; m_ptr = ptr; } }
// 检查是否拥有资源 explicit operator bool() const { return m_ptr != nullptr; } };
// 辅助函数:创建智能指针,类似于std::make_unique template <typename T, typename... Args> SmartPtr<T> make_smart(Args&&... args) { return SmartPtr<T>(new T(std::forward<Args>(args)...)); }
#endif // SMART_PTR_H
|
核心特性与设计思路
SmartPtr的核心是独占所有权:同一时间只能有一个智能指针管理资源,当指针生命周期结束时,自动释放资源。主要通过以下方式实现:
- 禁止复制(避免多个指针管理同一资源,导致重复释放);
- 允许移动(通过转移所有权,支持资源在指针间传递);
- 析构函数自动释放资源(RAII 的核心体现)。
关键成员与函数解析
1. 私有成员
1
| T* m_ptr; // 指向管理的资源(原始指针)
|
2. 构造与析构函数
1
| explicit SmartPtr(T* ptr = nullptr) : m_ptr(ptr) {}
|
1 2 3 4
| ~SmartPtr() { delete m_ptr; // 自动释放资源 m_ptr = nullptr; }
|
- RAII 的核心:当SmartPtr对象销毁时(如离开作用域),自动调用delete释放m_ptr指向的资源,避免内存泄漏。
3. 所有权控制(复制与移动)
为保证独占性,禁止复制、允许移动:
1 2
| SmartPtr(const SmartPtr& other) = delete; SmartPtr& operator=(const SmartPtr& other) = delete;
|
用= delete删除复制构造和复制赋值运算符,防止通过复制产生多个管理同一资源的智能指针(否则析构时会重复释放)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| // 移动构造:转移源对象的所有权 SmartPtr(SmartPtr&& other) noexcept : m_ptr(other.m_ptr) { other.m_ptr = nullptr; // 源对象放弃所有权(避免重复释放) }
// 移动赋值:先释放当前资源,再转移源对象的所有权 SmartPtr& operator=(SmartPtr&& other) noexcept { if (this != &other) { // 避免自赋值 delete m_ptr; // 释放当前资源 m_ptr = other.m_ptr; // 接管源对象的资源 other.m_ptr = nullptr; // 源对象放弃所有权 } return *this; }
|
移动操作通过右值引用(&&)实现,将资源从一个SmartPtr转移到另一个,原指针不再拥有资源(m_ptr设为nullptr)。
4. 指针操作符重载
模拟原始指针的操作行为:
- operator*():返回资源的引用,支持*ptr形式访问。
1
| T& operator*() const { return *m_ptr; }
|
- operator->():返回资源的指针,支持ptr->member形式访问成员。
1
| T* operator->() const { return m_ptr; }
|
5. 资源管理辅助函数
- get():返回原始指针(谨慎使用,避免手动释放导致智能指针重复释放)。
1
| T* get() const { return m_ptr; }
|
- release():释放资源所有权,返回原始指针(调用后智能指针不再管理该资源,需手动释放)。
1 2 3 4 5
| T* release() { T* temp = m_ptr; m_ptr = nullptr; return temp; }
|
- reset():重置资源(释放当前资源,接管新资源)。
1 2 3 4 5 6
| void reset(T* ptr = nullptr) { if (m_ptr != ptr) { delete m_ptr; m_ptr = ptr; } }
|
- operator bool():检查是否持有有效资源(支持if (ptr)形式判断)。
1
| explicit operator bool() const { return m_ptr != nullptr; }
|
6. 辅助函数make_smart
类似std::make_unique,用于安全创建SmartPtr对象:
1 2 3 4
| template <typename T, typename... Args> SmartPtr<T> make_smart(Args&&... args) { return SmartPtr<T>(new T(std::forward<Args>(args)...)); }
|
- 优势:通过完美转发(std::forward)传递参数,直接在内部创建对象并包装为SmartPtr,避免手动调用new,更安全(减少内存泄漏风险)。
使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include "SmartPtr.h" #include <iostream>
class MyClass { public: MyClass(int x) : m_x(x) { std::cout << "MyClass constructed with " << x << std::endl; } ~MyClass() { std::cout << "MyClass destructed" << std::endl; } void print() { std::cout << "Value: " << m_x << std::endl; } private: int m_x; };
int main() { // 使用make_smart创建智能指针 SmartPtr<MyClass> ptr = make_smart<MyClass>(10); ptr->print(); // 调用成员函数 (*ptr).print(); // 解引用访问
// 移动所有权 SmartPtr<MyClass> ptr2 = std::move(ptr); if (!ptr) { // 原指针已失去资源 std::cout << "ptr is now null" << std::endl; }
// 重置资源 ptr2.reset(new MyClass(20)); ptr2->print();
return 0; // 离开作用域时,ptr2自动释放资源 }
|