智能指针的实现原理主要基于 RAII(Resource Acquisition Is Initialization,资源获取即初始化) 技术,通过对象的生命周期来管理动态分配的内存。其核心思想是:将资源的获取与对象的构造绑定,资源的释放与对象的析构绑定。这样,当智能指针对象离开作用域或被销毁时,会自动释放其管理的资源,从而避免内存泄漏。
1. std::unique_ptr(独占所有权)
核心原理:
unique_ptr 通过独占所有权机制确保同一时间只有一个指针拥有资源。它内部封装了一个原始指针,并通过禁用拷贝构造函数和拷贝赋值运算符(只允许移动语义)来实现独占性。
关键实现:
使用 delete 关键字禁用拷贝构造函数和拷贝赋值运算符。
允许通过移动构造函数和移动赋值运算符转移所有权。
在析构函数中调用 delete(或自定义的删除器)释放资源。
template <typename T>
class unique_ptr {
private:
T* ptr; // 内部原始指针
public:
explicit unique_ptr(T* p) : ptr(p) {}
~unique_ptr() { delete ptr; } // 析构时自动释放资源
// 禁用拷贝
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
// 允许移动
unique_ptr(unique_ptr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr; // 移动后原指针置空
}
unique_ptr& operator=(unique_ptr&& other) noexcept {
if (this != &other) {
delete ptr; // 释放当前资源
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
T* get() const { return ptr; }
T& operator*() const { return *ptr; }
// 其他成员函数...
};
2. std::shared_ptr(共享所有权)
核心原理:
shared_ptr 通过 引用计数(Reference Counting) 实现共享所有权。多个 shared_ptr 可以指向同一对象,引用计数记录当前有多少个 shared_ptr 指向该对象。当引用计数降为 0 时,对象被销毁。
关键实现:
内部维护一个 控制块(Control Block),包含:
指向资源的指针。
引用计数(use_count):记录当前有多少个 shared_ptr 指向资源。
弱引用计数(weak_count):记录 weak_ptr 的引用次数。
每次拷贝构造或赋值时,引用计数加 1;每次析构时,引用计数减 1。
当引用计数为 0 时,调用 delete(或自定义删除器)释放资源。
控制块本身是线程安全的(通过原子操作保证引用计数的修改是原子的)。
template <typename T>
class shared_ptr {
private:
T* ptr; // 指向资源的指针
ControlBlock* cb; // 控制块指针
public:
explicit shared_ptr(T* p) : ptr(p), cb(new ControlBlock) {
cb->use_count = 1;
}
// 拷贝构造函数:引用计数 +1
shared_ptr(const shared_ptr& other) : ptr(other.ptr), cb(other.cb) {
cb->use_count++;
}
// 析构函数:引用计数 -1,若为 0 则释放资源
~shared_ptr() {
if (--cb->use_count == 0) {
delete ptr;
if (cb->weak_count == 0) {
delete cb;
}
}
}
// 其他成员函数...
};
3. std::weak_ptr(弱引用)
核心原理:
weak_ptr 是为了解决 shared_ptr 的 循环引用问题 而设计的。它指向 shared_ptr 管理的资源,但不会增加引用计数。通过 weak_ptr 可以安全地观察资源是否存在,而不会影响其生命周期。
关键实现:
内部同样维护一个指向控制块的指针,但不操作引用计数(use_count),只操作弱引用计数(weak_count)。
需要通过 lock() 方法获取一个临时的 shared_ptr 来访问资源。如果资源已被释放,lock() 返回空指针。
template <typename T>
class weak_ptr {
private:
T* ptr;
ControlBlock* cb;
public:
weak_ptr(const shared_ptr<T>& sp) : ptr(sp.ptr), cb(sp.cb) {
cb->weak_count++;
}
~weak_ptr() {
cb->weak_count--;
if (cb->use_count == 0 && cb->weak_count == 0) {
delete cb; // 释放控制块
}
}
shared_ptr<T> lock() const {
if (cb->use_count > 0) {
return shared_ptr<T>(*this);
} else {
return nullptr;
}
}
};
4. 循环引用问题与 weak_ptr 的解决
问题场景:
两个对象互相持有对方的 shared_ptr,导致引用计数永远无法降为 0,资源无法释放。
解决方案:
将其中一个 shared_ptr 替换为 weak_ptr。weak_ptr 不会增加引用计数,因此不会阻止资源的释放。

被折叠的 条评论
为什么被折叠?



