什么是智能指针
这三种智能指针都定义在memory头文件中。
C++的智能指针其实就是对普通指针的封装(即封装成一个类),通过重载 * 和 ->两个运算符,使得智能指针表现的就像普通指针一样。
智能指针实现原理
智能指针(smart pointer)的通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。每次创建类的新对象时,初始化指针就将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。
- shared_ptr
利用引用计数->每有一个指针指向相同的一片内存时,引用计数+1,每当一个指针取消指向一片内存时,引用计数-1,减为0时释放内存。
在典型的实现中,shared_ptr 只保有两个指针:
- get()所返回的指针;(基础对象的内存地址)
- 指向控制块的指针。(控制块对象的内存地址)
控制块是一个动态分配的对象,其中包含:
- 指向被管理对象的指针或被管理对象本身;(基础对象的内存地址)
- 删除器;(Deleter,类型擦除)
- 分配器;(Allocator,类型擦除)
- 占用被管理对象的shared_ptr的数量(
strong refs
强引用的引用计数); - 涉及被管理对象的weak_ptr的数量(
weak refs
弱引用的引用计数) 。
- week_ptr
弱指针 ->辅助shared_ptr解决循环引用的问题
weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源 (也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr 获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
- unique_ptr
“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(禁止拷贝、赋值),可以释放所有权,转移所有权。
unique_ptr实现对基础对象资源的独占,实现原理是将unique_ptr类的“拷贝构造函数”、“拷贝赋值运算符”均声明为delete,因此无法实施拷贝和赋值操作,但是可以“移动构造”和“移动赋值”。 转移一个unique_ptr将会把所有权也从源指针转移给目标指针(源指针被置为空)。
unique_ptr必须直接初始化,且不能通过隐式转换来构造,因为unique_ptr的构造函数被声明为explicit。
unique_ptr 的常用操作:
u.get(); //返回unique_ptr中保存的裸指针
u.reset(); //重置unique_ptr
u.release(); //放弃指针的控制权,返回裸指针,并将unique_ptr自身置为空。
u.swap(); //交换两个unique_ptr所指向的对象
#include <atomic>
using namespace std;
// shared_ptr()
namespace shp {
// 定义一个 callable对象类作为默认删除器
template<typename T>
class deafult_deleter {
public:
void operator()(T* ptr) {
delete ptr;
}
};
template<typename T, typename deleter = deafult_deleter<T>>
class shared_ptr {
private:
// 原生指针
T ptr = nullptr;
// 指向 count的指针,事实上 count本是更复杂的结构体其中一个成员,所以用指针保留扩展性
std::atomic<int>* count = nullptr; // 每个 std::atomic 模板的实例化和全特化定义一个原子类型
public:
// 默认构造函数
shared_ptr() = default; // 在非模板中,仅当您希望该类支持该操作(然后测试它是否支持)时才使用 =default ,关键字 =default 优化了这种行为,用该关键字标记重写的默认拷贝构造函数,编译器会隐式生成一个版本
// 原生指针构造
shared_ptr(T* _ptr);
// 拷贝构造函数
shared_ptr(const shared_ptr& lsh);
// 移动构造函数
shared_ptr(shared_ptr&& lsh);
// 拷贝赋值运算符
shared_ptr& operator=(const shared_ptr& lsh);
// 移动赋值运算符
shared_ptr& operator= (shared_ptr&& lsh);
// 析构接口
~shared_ptr();
// 箭头函数运算符重载
T* operator->();
// 解引用运算符重载
T& operator*();
// 智能指针交换接口
void swap(shared_ptr& lsh);
// 解除对当前指针的管理,如果有新的 ptr则托管新的指针
void reset(T* _ptr = nullptr);
// 获取引用计数
int count();
// 获取原生指针
T* get();
};
// 原生指针构造
template<typename T, typename deleter>
shared_ptr<T, deleter>::shared_ptr(T* _ptr):ptr(_ptr), count(new atomic<int>(1)){}
// 拷贝构造函数
template<typename T,typename deleter>
shared_ptr<T, deleter>::shared_ptr(const shared_ptr& lsh) {
ptr = lsh.ptr;
count = lsh.count;
++* count;
}
// 移动构造函数
template<typename T, typename deleter>
shared_ptr<T, deleter>::shared_ptr(shared_ptr&& lsh) {
swap(ptr, lsh.ptr);
swap(count, lsh.count)
}
// 拷贝赋值运算符,使用 copy&swap的方式实现自赋值
template<typename T,typename deleter>
shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(const shared_ptr& lsh) {
shared_ptr<T, deleter> lsh_copy(lsh);
swap(lsh_copy);
return *this;
}
// 移动赋值运算符
template<typename T, typename deleter>
shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator*(shared_ptr&& lsh) {
if (this != &lsh) { // 避免自我赋值
// 如果原本有托管对象
if (ptr) {
--* count;
if (*count <= 0) {
deleter()(ptr);
deleter count;
}
ptr = nullptr;
count = nullptr;
}
swap(lsh);
}
return *this;
}
// 析构接口
template<typename T, typename deleter>
shared_ptr<T, deleter>::~shared_ptr() {
if (ptr) {
--* count;
if (*count <= 0) {
deleter()(ptr);
deleter count;
}
}
}
// 箭头运算符重载
template<typename T, typename deleter>
T* shared_ptr<T, deleter>::operator->() {
return ptr;
}
// 解引用运算符重载
template<typename T, typename deleter>
T& shared_ptr<T, deleter>::operator*() {
return *ptr;
}
// swap交换
template<typename T, typename deleter>
void shared_ptr<T, deleter>::swap(shared_ptr& lsh) {
swap(ptr, lsh.ptr);
swap(count, lsh.count);
}
// 解除当前指针的管理,如果有新的 ptr则托管新的指针
template<typename T, typename deleter>
void shared_ptr<T, deleter>::reset(T* _ptr) {
if (ptr) { // 如果当前 shared_ptr 有托管对象,先释放原托管
--*count;
if (*count <= 0) {
deleter()(ptr);
deleter count;
}
ptr = nullptr;
count = nullptr;
}
// 是否有新托管
if (_ptr) {
ptr = _ptr;
count = mew atomic<int>(1);
}
}
// 获取引用计数
template<typename T, typename deleter>
int shared_ptr<T, deleter>::count() {
return *count;
}
// 获取原生指针
template<typename T, typename deleter>
T* shared_ptr<T, deleter>::get() {
return ptr;
}
template <typename T>
class unique_ptr {
private:
T* ptr = nullptr;
public:
// 普通构造
unique_ptr(T* p = nullptr) : ptr(p) {
}
// 析构
~unique_ptr() {
if (nullptr != this->ptr) {
delete this->ptr;
this->ptr = nullptr;
}
}
// 移动构造
unique_ptr(unique_ptr&& obj) : unique_ptr() {
*this = ::std::move(obj);
}
// 移动赋值
unique_ptr& operator=(unique_ptr&& rhs) {
if (this == &rhs) {
return *this;
}
// 夺取右值的资源
this->~unique_ptr();
this->ptr = rhs.ptr;
rhs.ptr = nullptr;
return *this;
}
public: // 修改器
// 返回一个指向被管理对象的指针,并释放所有权
T* release() {
T* res = this->ptr;
this->ptr = nullptr;
return res;
}
// 替换被管理对象
void reset(T* p = nullptr) {
// 直接调用operator=
*this = unique_ptr<T>(p);
}
// 交换被管理对象
void swap(unique_ptr& other) {
::std::swap(this->ptr, other.ptr);
}
public: // 观察器
// 返回指向被管理对象的指针
T* get() {
return this->ptr;
}
// 返回用于析构被管理对象的删除器
// 本简单样例不考虑删除器
// D& get_deleter();
// 检查是否有关联的被管理对象
operator bool() {
return nullptr != get();
}
// operator*
T& operator*() {
assert(get());
return *this->ptr;
}
// operator->
T* operator->() {
assert(get());
return this->ptr;
}
};
template<class T>
class weak_ptr {
public:
using element_type = remove_extent_t<T>;
// 构造函数接口
constexpr weak_ptr() noexcept { // 静态编译关键字 constexpr 表示它所声明的变量或者函数,都在静态编译时就已经完成
ptr = 0;
count = 0;
}
template(class Y)weak_ptr(const shared_ptr<Y>& w) noexcept :ptr(s.ptr), count(s.count) { // noexcept 表示无需抛出异常 noexcept(false) 表示抛出异常 throw(...)表示接收任何类型异常
count->w++;
}
weak_ptr(const weak_ptr& w) noexcept;
template<class Y> weak_ptr(const weak_ptr<Y>& w) noexcept :ptr(w.ptr), count(w.count) {
count->w++;
}
weak_ptr(weak_ptr&& w) noexcept;
template<class Y>weak_ptr(weak_ptr<Y>&& w) noexcept;
// 析构函数接口
~weak_ptr() {
release();
}
// 赋值构造函数
weak_ptr& operator=(const weak_ptr& w) noexcept;
template<class Y> weak_ptr& operator=(const weak_ptr<Y>& w) noexcept {
if (this != &w) {
release();
count = w.count;
count->w++;
ptr = w.ptr;
}
return *this;
}
template<class Y>weak_ptr& operator=(const shared_ptr<Y>& w) noexcept {
release();
count = w.count;
count->w++;
ptr = w.ptr;
return *this;
}
weak_ptr& operator=(weak_ptr&& w) noexcept;
template<class Y> weak_ptr& operato = (weak_ptr<Y> && w) noexcept;
// 接口 swap互换同类型的 weak_ptr 指针
void swap(weak_ptr& w) noexcept;
// 将当前 weak_ptr指针置为空指正
void reset() noexcept;
// 查看指向和当前 weak_ptr指针相同的 shared_ptr指针的数量
long count() const noexcept;
// 判断当前 weak_ptr指针是否过期(指针为空,或者指向的堆内存已经被释放)
bool expired() const noexcept {
if (count) {
if (count->s > 0) {
return false;
}
}
return true;
}
// 如果当前 weak_ptr已经过期,则该函数会返回一格空的 shared_ptr指针,反之该函数返回一格和当前 weak_ptr指向相同 shared_ptr指针
shared_ptr<T> lock() const noexcept {
return shared_ptr<T> (*this);
}
template<class U>
bool owner_before(const shared_ptr<U>& b) const noexcept;
template<class U>
bool owner_before(const weak_ptr<U>& b) const noexcept;
friend class shatred_ptr<T>;
private:
void release() {
if (count) {
count->w--;
if (count->w < 1 && count->s < 1) {
count = nullptr;
}
}
}
T* ptr;
cpimter* count;
};
}