智能指针是C++中用于管理动态内存的工具,本质是一个封装了原始指针的类,通过RAII机制在对象生命周期结束时自动释放资源,从而避免内存泄漏。
其中unique_ptr表示独占所有权,shared_ptr通过引用计数实现共享所有权,weak_ptr用于解决shared_ptr循环引用的问题。
RAII:资源获取即初始化
在对象的构造函数中申请并分配资源。
利用 C++ 局部对象生命周期结束时自动调用析构函数的特性,在析构函数中释放资源。
#include <atomic>
#include <utility> //swap
#include <iostream>
template <typename T>
class SharedPtr
{
public:
//构造
explicit SharedPtr(T* ptr = nullptr)
: ptr_(ptr),
ref_count_(nullptr)
{
if (ptr_ != nullptr)
{
ref_count = new std::atomic<int>(1);
}
}
//拷贝构造
SharedPtr(const SharedPtr& other)
: ptr_(other.ptr_),
ref_count_(other.ref_count_)
{
if (ref_count_ != nullptr)
{
ref_count_ -> fetch_add(1, std::memory_order_relaxed);
}
}
//移动构造
SharedPtr(SharedPtr&& other) noexcept
: ptr_(other.ptr_),
ref_count_(other.ref_count_)
{
other.ptr_ = nullptr;
other.ref_count = nullptr;
}
//拷贝赋值
SharedPtr& operator=(const SharedPtr& other)
{
if (this != &other)
{
//先减少当前对象的引用计数
release();
//复制新对象
ptr_ = other.ptr_;
ref_count_ = other.ref_count_;
if (ref_count_ != nullptr)
{
ref_count_->fetch_add(1, std::memory_order_relaxed);
}
}
return *this;
}
//移动赋值
SharedPtr& operator=(SharedPtr&& other)
{
if (this != &other)
{
release();
ptr_ = other.ptr_;
ref_count_ = other.ref_count_;
other.ptr_ = nullptr;
other.ref_count_ = nullptr;
}
return *this;
}
//析构
~SharedPtr()
{
release();
}
//解引用
T& operator*() const
{
return *ptr_;
}
T* operator->() const{
return ptr_;
}
//获取原始指针
T* get() const
{
return ptr_;
}
//获取引用计数
int use_count() const
{
return ref_count_ != nullptr ? ref_count_->load(std::memory_order_relaxed) : 0;
}
//检查是否独占
bool unique() const
{
return use_count() == 1;
}
//重置
void reset(T* ptr = nullptr)
{
release();
ptr_ = ptr;
if (ptr_ != nullptr)
{
ref_count_ = new std::atomic<int>(1);
}
else{
ref_count_ = nullptr;
}
}
//交换
void swap(SharedPtr& other)
{
std::swap(ptr_, other.ptr_);
std::swap(ref_count_, other.ref_count_);
}
private:
void release()
{
if (ref_count_ != nullptr)
{
//减少引用计数
int old_count = ref_count_->fetch_sub(1, std::memory_order_acq_rel);
//最后一个引用,删除资源
if (old_count == 1)
{
delete ptr_;
delete ref_count_;
}
}
ptr_ = nullptr;
ref_count_ = nullptr;
}
private:
T* ptr_;
std::atomic<int>* ref_count_;
};