优酷网站怎么做的,做表格的网站,怎样在在农行网站上做风险评估,哈尔滨快速网站排名文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. rele… 文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. release函数, 指针的delete 和 设置为nullptr6. 获取内部变量, 指针和引用 简介
git地址: shimachao/smart_ptr说明: 这是一个仿写shared_ptr的库, 只有简短的200行, 实现了shared_ptr的大部分功能, 上手简单, 非常适合新手阅读.本文说明: 由于本项目没有那么多难点, 就不再像上篇开源代码阅读中c源码阅读__ThreadPool__正文阅读一样, 不单独开一个前提知识部分了, 由于本项目比较简单, 大家就当作对shared_ptr的一次复习. 看一乐呵就行.
源码
此代码在c20环境下直接可以运行, 源码如下
#pragma once#include functional// 模仿shared_ptr实现一个智能指针
template typename T
class smart_ptr
{
public:smart_ptr();explicit smart_ptr(T*);smart_ptr(const smart_ptr);smart_ptr(T*, std::functionvoid(T*));smart_ptr operator(const smart_ptr);T operator*() const;T* operator-() const;~smart_ptr();// 向bool的类型转换explicit operator bool() const;bool unique();void reset();void reset(T*);void reset(T*, std::functionvoid(T*));T* release();T* get() const;private:// 默认的deleterstatic std::functionvoid(T*) default_del;private:unsigned* m_p_use_count nullptr;T* m_pobject nullptr;std::functionvoid(T*) m_del default_del;
};template typename T
std::functionvoid(T*) smart_ptrT::default_del [](T*p) {delete p; p nullptr; };template typename T, typename... Args
smart_ptrT make_smart(Args... args)
{smart_ptrT sp(new T(std::forwardArgs(args)...));return sp;
}template typename T
smart_ptrT::smart_ptr():m_pobject(nullptr), m_p_use_count(new unsigned(1))
{
}template typename T
smart_ptrT::smart_ptr(T *p):m_pobject(p), m_p_use_count(new unsigned(1))
{
}template typename T
smart_ptrT::smart_ptr(T *p, std::functionvoid(T*) del):m_pobject(p), m_p_use_count(new unsigned(1)), m_del(del)
{
}template typename T
smart_ptrT::smart_ptr(const smart_ptr rhs):m_pobject(rhs.m_pobject), m_p_use_count(rhs.m_p_use_count), m_del(rhs.m_del)
{(*m_p_use_count);
}template typename T
smart_ptrT smart_ptrT::operator (const smart_ptr rhs)
{// 使用rhs的deleterm_del rhs.m_del;// 递增右侧运算对象的引用计数(*rhs.m_p_use_count);// 递减本对象的引用计数if (--(*m_p_use_count) 0){// 如果管理的对象没有其他用户了则释放对象分配的成员m_del(m_pobject);delete m_p_use_count;}m_p_use_count rhs.m_p_use_count;m_pobject rhs.m_pobject;return *this; // 返回本对象
}template typename T
T smart_ptrT::operator*() const
{return *m_pobject;
}template typename T
T* smart_ptrT::operator-() const
{return this-operator*();
}template typename T
smart_ptrT::~smart_ptr()
{if (--(*m_p_use_count) 0){m_del(m_pobject);m_pobject nullptr;delete m_p_use_count;m_p_use_count nullptr;}
}template typename T
bool smart_ptrT::unique()
{return *m_p_use_count 1;
}template typename T
void smart_ptrT::reset()
{(*m_p_use_count)--;if (*m_p_use_count 0){m_del(m_pobject);}m_pobject nullptr;*m_p_use_count 1;m_del default_del;
}template typename T
void smart_ptrT::reset(T* p)
{(*m_p_use_count)--;if (*m_p_use_count 0){m_del(m_pobject);}m_pobject p;*m_p_use_count 1;m_del default_del;
}template typename T
void smart_ptrT::reset(T *p, std::functionvoid(T*) del)
{reset(p);m_del del;
}template typename T
T* smart_ptrT::release()
{(*m_p_use_count)--;if (*m_p_use_count 0){*m_p_use_count 1;}auto p m_pobject;m_pobject nullptr;return p;
}template typename T
T* smart_ptrT::get() const
{return m_pobject;
}template typename T
smart_ptrT::operator bool() const
{return m_pobject ! nullptr;
}解析
这里会把smart_ptr类中每一部分都单独拿出来说明, 并进行举例
1. 引用计数的实现方式
我们可以看到他的实现方式
unsigned* m_p_use_count nullptr;使用的是整数的指针, 如果不使用指针的话, 那么是打不到公用引用计数的效果的, 如下
int* a1 new int(1);
int* a2 a1;
*a2 1;
cout *a1 endl;
cout *a2 endl;int a3 1;
int a4 a3;
a3 1;
cout a4 endl;
cout a4 endl;int a5 1;
int a6 a5;
a5;
cout a5 endl;
cout a6 endl;执行结果 那么我们是不是也可以用引用来实现引用计数的共用呢? 我觉得是可以的
2. deleter静态方法的赋值时间节点
template typename T
class smart_ptr
{
private:// 默认的deleterstatic std::functionvoid(T*) default_del;std::functionvoid(T*) m_del default_del;
}
template typename T
std::functionvoid(T*) smart_ptrT::default_del [](T*p) {delete p; p nullptr; };静态方法的赋值, 是 程序启动并进入主函数之前进行赋值的, 具体地这个初始化是在包含这行代码的翻译单元被加载时完成的, 所以 default_del在任何smart_ptr的构造函数调用之前就赋值了. m_del的赋值是在smart_ptr的构造函数被调用时赋值的
3.make_smart的实现方式 与 好处
template typename T, typename... Args
smart_ptrT make_smart(Args... args)
{smart_ptrT sp(new T(std::forwardArgs(args)...));return sp;
}这里右值引用和完美转发相关的知识在左值右值, 左值引用右值引用,完美转发这篇博客中有详细介绍. 这里和shared_ptr一样, 也是接收目标类的构造函数的参数, 直接返回智能指针的实现方式 好处: 我们使用make_smart的方式, 创建智能指针非常好, 因为不用我们手动new一个指针出来, 那么智能指针外部就没有该指针的变量, 就不会造成一些未知错误, 保证了在指针的生命周期内, 都是被智能指针安全管理的.
4. 几种构造函数
常用的构造函数和赋值运算符 在这篇文章里有介绍 C基础知识对象移动拷贝构造函数移动拷贝构造函数赋值运算符移动赋值运算符
4.1 空构造函数
template typename T
smart_ptrT::smart_ptr():m_pobject(nullptr), m_p_use_count(new unsigned(1))
{}这个方法是构造一个内容为空的智能指针, 声明方式如下 smart_prtMyClass sp(); 这个可以配合后面的reset方法使用, 给智能指针重新赋值
4.2 接收指针的构造函数
template typename T
smart_ptrT::smart_ptr(T *p):m_pobject(p), m_p_use_count(new unsigned(1))
{}使用方式如下, 但是不推荐这种方式, 因为外部有了指针变量s1, 这就给智能指针的管理带来了未知的风险
MyStruct* s1 new MyStruct(1, 2);
smart_ptrMyStruct sp(s1);4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写
template typename T
smart_ptrT::smart_ptr(T *p, std::functionvoid(T*) del):m_pobject(p), m_p_use_count(new unsigned(1)), m_del(del)
{}这个构造方法就是上面4.2多加一个参数, 没什么好说的, 但是其中delete方法的传入, 我们可以通过auto来编写模板lambda, 这是c新的特性, 如下
auto deleter [](auto* p) {delete *p; p nullptr;};
MyStruct* s new MyStruct(1, 2);
smart_ptrMyStruct sp(s, deleter);这样, 我们就不用template写一大堆, 而直接构造出了一个模板函数
4.4 拷贝构造函数
拷贝构造函数, 会造成引用计数1, 两个智能指针指向的是同一块地址
template typename T
smart_ptrT::smart_ptr(const smart_ptr rhs) :m_pobject(rhs.m_pobject), m_p_use_count(rhs.m_p_use_count), m_del(rhs.m_del)
{(*m_p_use_count);
}符号的赋值, 是赋值的内容, 不是变量本身的地址设置为一致(这是引用的), 所以指针的, 是指针变量内指向的地址设置为相同
MyStruct* s1 new MyStruct(1, 2);
smart_ptrMyStruct sp(s1);
smart_ptrMyStruct sp2(sp);
cout std::boolalpha;
cout (sp.get() sp2.get()) endl;执行结果
4.5 赋值运算符
赋值运算符 和 拷贝构造函数就大不一样了, 赋值运算符会把等号左边的智能指针内的变量引用计数-1, 如果引用计数为0了, 还会释放资源
template typename T
smart_ptrT smart_ptrT::operator (const smart_ptr rhs)
{// 使用rhs的deleterm_del rhs.m_del;// 递增右侧运算对象的引用计数(*rhs.m_p_use_count);// 递减本对象的引用计数if (--(*m_p_use_count) 0){// 如果管理的对象没有其他用户了则释放对象分配的成员m_del(m_pobject);delete m_p_use_count;}m_p_use_count rhs.m_p_use_count;m_pobject rhs.m_pobject;return *this; // 返回本对象
}所以根据代码, 我们合理预测, 如果左边的智能指针引用计数如果是1的话, 那么使用了赋值运算符, 就会造成内部的指针析构 测试代码
struct MyStruct
{MyStruct() default;MyStruct(int a, int b) :a(a), b(b) {}~MyStruct() { cout ~MyStruct ( a , b ) endl;}int a;int b;
};int main()
{smart_ptrMyStruct sp1 make_smartMyStruct(1, 2);smart_ptrMyStruct sp2 make_smartMyStruct(3, 4);sp1 sp2;cout endl;return 0;
}执行结果
可以看到, 是sp1在程序结束之前析构的
5. release函数, 指针的delete 和 设置为nullptr
这里我们要明确,delete是把指针指向的内容进行析构, 而直接把指针设置为nullptr, 只是把当前这个指针变量设置为nullptr, 对于指针指向的内容, 不做任何处理 比如release函数
template typename T
T* smart_ptrT::release()
{(*m_p_use_count)--;if (*m_p_use_count 0){*m_p_use_count 1;}auto p m_pobject;m_pobject nullptr;return p;
}在这个函数里, 只是把m_pojbect这个指针变量本身设置为了nullptr, 而指针指向的变量没有做任何操作, 最后把这个指针变量copy一份, 返回出去了 测试代码
struct MyStruct
{MyStruct() default;MyStruct(int a, int b) :a(a), b(b) {}~MyStruct() { cout ~MyStruct ( a , b ) endl;}int a;int b;
};int main()
{smart_ptrMyStruct sp1 make_smartMyStruct(1, 2);MyStruct* s1 sp1.release();cout endl;delete s1;return 0;
}执行结果 可以看到, release确实没有造成析构
6. 获取内部变量, 指针和引用
有两个方法, 一个是重载的操作符*, 一个是get方法 只不过get获取的指针 *获取的是引用
template typename T
T smart_ptrT::operator*() const
{return *m_pobject;
}
template typename T
T* smart_ptrT::get() const
{return m_pobject;
}测试代码
int main()
{smart_ptrMyStruct sp1 make_smartMyStruct(1, 2);cout std::boolalpha endl;// (*sp1)获取了引用: MyStruct, 转为指针 *(MyStruct)cout ((*sp1) sp1.get()) endl;return 0;
}执行结果