当牛做吗网站源代码分享百度云,帝国怎么做网站,公司没有自己的网站,购物网页模板文章目录 4.智能指针[shared_ptr]4.1设计理念成员属性 4.2主要接口拷贝构造 4.3引用计数线程安全问题测试线程安全通过对计数引用的加锁保护使得类线程安全类实例化的对象使用时需要手动加锁保护 锁的引进线程引用传参问题 4.4整体代码 5.循环引用问题5.1问题的引入… 文章目录 4.智能指针[shared_ptr]4.1设计理念成员属性 4.2主要接口拷贝构造 4.3引用计数线程安全问题测试线程安全通过对计数引用的加锁保护使得类线程安全类实例化的对象使用时需要手动加锁保护 锁的引进线程引用传参问题 4.4整体代码 5.循环引用问题5.1问题的引入5.2分析造成此问题的原因5.3weak_ptr的主要代码 6.数组对象的删除问题6.1代码问题6.2std::shared_ptr面对此问题的解决方案1.首先看std::shared_ptr::~shared_ptr2.删除器的传参及使用3.添加封装删除器 7.总结7.1完整代码7.2C11和Boost智能指针的关系 4.智能指针[shared_ptr]
4.1设计理念
成员属性 每一个对象除了有一个主指针外 还有一个副指针用来计数 为什么不设置成int而设置成int*? 同一块空间被两个指针指向 当编译器得到需要销毁指针的指令时 会先判断这是不是最后一个指针 即count1 时才释放空间 其余情况均只是的计数-- 而不释放空间 这是我们的最初目的 如果设置成int意味着每一个对象有各自的count 当ptr1拷贝给ptr2 我们想要的是 有一块空间单独来计数 如果执行拷贝则计数 即我们需要一块共有的空间来实现 不是要实现共有吗 为什么不直接用静态变量? 静态变量可以实现共有没错 但他是当前类的所有对象共有 举例说明: 代码的本意是ptr1 ptr2 ptr3指向同一块空间 此时count 3 ptr4指向另一块空间时 代码的本意是count 1 但是同时改变了ptr1/2/3
4.2主要接口
拷贝构造 //赋值重载//1.自己给自己赋值//不仅仅是p1 p1 还要考虑p2 p1 但之前p2就 p1//2.左 右 赋值后 // 左指针指向空间的指针少了一个 左指针的count-- 进一步考虑count--后0的情况// 右指针指向空间的指针多了一个 右指针的countshared_ptrT operator(const shared_ptrT sp){//自己给自己赋值: 自己的本质if (_ptr ! sp._ptr){//count--Release();_ptr sp._ptr;_pcount sp._pcount;_pmtx sp._pmtx;//countAddCount();}return *this;}4.3引用计数线程安全问题
测试线程安全
通过对计数引用的加锁保护使得类线程安全 struct Date{int _year 0;int _month 0;int _day 0;};void SharePtrFunc(ape::shared_ptrDate sp, size_t n, mutex mtx){cout SharePtrFunc: sp.GetPtr() sp.GetPtr() endl;for (size_t i 0; i n; i){ape::shared_ptrDate copy(sp);}}void test_shared_safe(){ape::shared_ptrDate p(new Date);cout test_shared_safe: p.GetPtr() p.GetPtr() endl;const size_t n 10000;mutex mtx;//线程引用传参即便mtx已经是引用 此处仍然需要使用库函数ref();thread t1(SharePtrFunc, ref(p), n, ref(mtx));thread t2(SharePtrFunc, ref(p), n, ref(mtx));t1.join();t2.join();cout p.GetCount(): p.GetCount() endl;}类实例化的对象使用时需要手动加锁保护 锁的引进 线程引用传参问题 简单理解为 p在传给sp前是需要先调用线程的构造函数的 期间发生了某种动作 使得失去引用属性 4.4整体代码
templateclass T
class shared_ptr
{
public://构造函数shared_ptr(T* ptr):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex){}void Release(){//上锁_pmtx-lock();//不可释放锁bool deleteFlag false;if (--(*_pcount) 0){cout delete: _ptr endl;delete _ptr;delete _pcount;//可释放锁deleteFlag true;}//解锁_pmtx-unlock();//判断并释放锁if (deleteFlag){delete _pmtx;}}//void Release()//{// _pmtx-lock();// bool deleteFlag false;// if (--(*_pcount) 0)// {// if (_ptr)// {// //cout delete: _ptr endl;// //delete _ptr;//// // 删除器进行删除// _del(_ptr);// }//// delete _pcount;// deleteFlag true;// }//// _pmtx-unlock();//// if (deleteFlag)// {// delete _pmtx;// }//}void AddCount(){_pmtx-lock();(*_pcount);_pmtx-unlock();}//拷贝构造shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx){AddCount();}//赋值重载//1.自己给自己赋值//不仅仅是p1 p1 还要考虑p2 p1 但之前p2就 p1//2.左 右 赋值后 // 左指针指向空间的指针少了一个 左指针的count-- 进一步考虑count--后0的情况// 右指针指向空间的指针多了一个 右指针的countshared_ptrT operator(const shared_ptrT sp){//自己给自己赋值: 自己的本质if (_ptr ! sp._ptr){//count--Release();_ptr sp._ptr;_pcount sp._pcount;_pmtx sp._pmtx;//countAddCount();}return *this;}//析构函数~shared_ptr(){Release();}T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* GetPtr(){return _ptr;}int GetCount(){return *_pcount;}private:T* _ptr;int* _pcount;mutex* _pmtx;
};void test_shared()
{shared_ptrint sp1(new int(1));shared_ptrint sp2(sp1);shared_ptrint sp3(sp2);shared_ptrint sp4(new int(10));sp1 sp4;sp4 sp1;sp1 sp1;sp1 sp2;
}// 线程安全问题 ///
struct Date
{int _year 0;int _month 0;int _day 0;
};void SharePtrFunc(ape::shared_ptrDate sp, size_t n, mutex mtx)
{cout SharePtrFunc: sp.GetPtr() sp.GetPtr() endl;cout SharePtrFunc: sp sp endl;for (size_t i 0; i n; i){ape::shared_ptrDate copy(sp);mtx.lock();sp-_year;sp-_day;sp-_month;mtx.unlock();}
}void test_shared_safe()
{ape::shared_ptrDate p(new Date);cout test_shared_safe: p.GetPtr() p.GetPtr() endl;cout test_shared_safe: p p endl;const size_t n 100000;mutex mtx;//线程引用传参即便p和mtx已经是引用 此处仍然需要使用库函数ref();thread t1(SharePtrFunc, ref(p), n, ref(mtx));thread t2(SharePtrFunc, ref(p), n, ref(mtx));t1.join();t2.join();cout p.GetCount(): p.GetCount() endl;cout p-_year p-_year endl;cout p-_month p-_month endl;cout p-_month p-_month endl;}5.循环引用问题
5.1问题的引入 5.2分析造成此问题的原因 为了解决此问题 需要引进weaked_ptr 我们需要了解的是 智能指针shared_ptr满足 符合RAII思想可以像指针一样使用支持拷贝 智能指针weaked_ptr满足 不符合RAII思想可以像指针一样使用辅助解决shared_ptr的循环引用问题weaked_ptr可以指向资源但是不参与管理不增加引用计数 实际上库里的智能指针远比我们上述讲到的复杂得多 为了便于学习和理解 我们只学习核心框架 需要了解的是 库里所支持的这两个函数 weaked_ptr有自己的count 配合expired来判断所指向资源是否还有被指向的必要 即weaked_ptr可以指向资源但是不参与管理不增加shared_ptr引用计数 所以存在于一种所指向资源的计数已经成0 此时expired判断是否失效 若所指向资源失效weaked_ptr就不再指向 5.3weak_ptr的主要代码
templateclass T
class weak_ptr
{
public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptrT sp):_ptr(sp.GetPtr()){}T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* GetPtr(){return _ptr;}private:T* _ptr;
};6.数组对象的删除问题
6.1代码问题 ape::shared_ptrDate sparr(new Date[10]); 当使用我们自己模拟实现的简洁版shared_ptr时 上述代码会报错(手动实现Date的析构函数时会报错 不手动实现调用库的析构函数不报错 因为当手动实现了析构函数 Date的空间前会有一个4字节的空间用来存放实例化对象的个数 以便知道调用几次析构函数 但是此时析构函数应该先向前偏移4字节 以便析构时把这4个字节也释放 6.2std::shared_ptr面对此问题的解决方案
1.首先看std::shared_ptr::~shared_ptr 即库里的shared_ptr::~shared_ptr与我们写的析构函数不同之处在于 一个对象在实例化时 他会判断是否接受了参数deleter 如果接收则析构时调用deleter析构 若没有接收deleter则正常析构 2.删除器的传参及使用 销毁对象。但是以前根据成员use_count的值它可能会产生以下副作用如果use_count大于1即该对象与其他shared_ptr对象共享其托管对象的所有权与其共享所有权的其他对象的使用计数将减少1。如果use_coount为1即该对象是托管指针的唯一所有者它所拥有的指针被删除如果shared_ptr对象是用特殊的deleter构造的则调用它否则函数使用运算符delete。如果use_count为零即对象为空则此析构函数没有副作用。 templateclass Tstruct DeleteArray{void operator()(T* ptr){cout 匿名对象DeleteArrayDate(): ptr endl;delete[] ptr;}};void test_std_shared_deletor(){//template class U, class D //shared_ptr (U* p, D del); 带删除器的构造函数std::shared_ptrDate sparr1(new Date[10], DeleteArrayDate());std::shared_ptrDate sparr2(new Date[10],[](Date* ptr){cout lambda表达式 delete[]: ptr endl;delete[] ptr;});auto deleter [](Date* ptr){cout lambda表达式 delete[]: ptr endl;delete[] ptr;};std::shared_ptrDate sparr3(new Date[10], deleter);std::shared_ptrFILE spFile(fopen(Test.cpp, r),[](FILE* ptr){cout lambda表达式 delete[]: ptr endl;fclose(ptr);});}3.添加封装删除器 7.总结
7.1完整代码
#pragma once#include mutex
#include thread
#include memorynamespace ape
{templateclass Tclass shared_ptr{public://构造函数shared_ptr(T* ptr nullptr):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex){}//删除器构造函数templateclass Dshared_ptr(T* ptr, D del):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex), _del(del){}//非删除器Release()/*void Release(){//上锁_pmtx-lock();//不可释放锁bool deleteFlag false;if (--(*_pcount) 0){if (_ptr ! nullptr){cout delete: _ptr endl;delete _ptr;}delete _pcount;//可释放锁deleteFlag true;}//解锁_pmtx-unlock();//判断并释放锁if (deleteFlag){delete _pmtx;}}*///删除器Release()void Release(){_pmtx-lock();bool deleteFlag false;if (--(*_pcount) 0){if (_ptr ! nullptr){_del(_ptr);}delete _pcount;deleteFlag true;}_pmtx-unlock();if (deleteFlag){delete _pmtx;}}void AddCount(){_pmtx-lock();(*_pcount);_pmtx-unlock();}//拷贝构造shared_ptr(const shared_ptrT sp):_ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx){AddCount();}//赋值重载//1.自己给自己赋值//不仅仅是p1 p1 还要考虑p2 p1 但之前p2就 p1//2.左 右 赋值后 // 左指针指向空间的指针少了一个 左指针的count-- 进一步考虑count--后0的情况// 右指针指向空间的指针多了一个 右指针的countshared_ptrT operator(const shared_ptrT sp){//自己给自己赋值: 自己的本质if (_ptr ! sp._ptr){//count--Release();_ptr sp._ptr;_pcount sp._pcount;_pmtx sp._pmtx;//countAddCount();}return *this;}//析构函数~shared_ptr(){Release();}T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* GetPtr() const{return _ptr;}int GetCount() const{return *_pcount;}private:T* _ptr;int* _pcount;mutex* _pmtx;//包装器//缺省值处理情况: ape::shared_ptrDate sp(new Date);//因为你析构时默认使用删除器 那么遇到没有显示传的要使用缺省值//构造函数传deleter时 可以是仿函数 lambda表达式 函数指针 此处用包装器接收functionvoid(T*) _del [](T* ptr){cout lambda表达式 delete: ptr endl;delete ptr;};};void test_shared(){shared_ptrint sp1(new int(1));shared_ptrint sp2(sp1);shared_ptrint sp3(sp2);shared_ptrint sp4(new int(10));sp1 sp4;sp4 sp1;sp1 sp1;sp1 sp2;}// 线程安全问题 ///struct Date{int _year 0;int _month 0;int _day 0;~Date(){}};void SharePtrFunc(ape::shared_ptrDate sp, size_t n, mutex mtx){cout SharePtrFunc: sp.GetPtr() sp.GetPtr() endl;cout SharePtrFunc: sp sp endl;for (size_t i 0; i n; i){ape::shared_ptrDate copy(sp);mtx.lock();sp-_year;sp-_day;sp-_month;mtx.unlock();}}void test_shared_safe(){ape::shared_ptrDate p(new Date);cout test_shared_safe: p.GetPtr() p.GetPtr() endl;cout test_shared_safe: p p endl;const size_t n 100000;mutex mtx;//线程引用传参即便p和mtx已经是引用 此处仍然需要使用库函数ref();thread t1(SharePtrFunc, ref(p), n, ref(mtx));thread t2(SharePtrFunc, ref(p), n, ref(mtx));t1.join();t2.join();cout p.GetCount(): p.GetCount() endl;cout p-_year p-_year endl;cout p-_month p-_month endl;cout p-_month p-_month endl;}templateclass Tclass weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptrT sp):_ptr(sp.GetPtr()){}T operator*(){return *_ptr;}T* operator-(){return _ptr;}T* GetPtr(){return _ptr;}private:T* _ptr;};// 循环引用struct ListNode{/*普通写法ListNode* _next;ListNode* _prev;int _val;*//*shared_ptrape::shared_ptrListNode _next;ape::shared_ptrListNode _prev;int _val;*///weaked_ptrape::weak_ptrListNode _next;ape::weak_ptrListNode _prev;int _val;~ListNode(){cout ~ListNode() endl;}};// 循环引用void test_shared_cycle(){/*常规写法 -- 抛异常场景不适合ListNode* n1 new ListNode;ListNode* n2 new ListNode;n1-_next n2;n2-_prev n1;delete n1;delete n2;*///智能指针写法ape::shared_ptrListNode n1(new ListNode);ape::shared_ptrListNode n2(new ListNode);//内置类型 自定义类型 -- error/*ListNode* _next;ListNode* _prev;int _val;ape::shared_ptrListNode n1(new ListNode);ape::shared_ptrListNode n2(new ListNode);n1-_next n2;n2-_prev n1;*//*shared_ptr: 引发循环引用问题ape::shared_ptrListNode _next;ape::shared_ptrListNode _prev;int _val;ape::shared_ptrListNode n1(new ListNode);ape::shared_ptrListNode n2(new ListNode);n1-_next n2;n2-_prev n1;*//*weak_ptr: 解决循环引用ape::weak_ptrListNode _next;ape::weak_ptrListNode _prev;int _val;ape::shared_ptrListNode n1(new ListNode);ape::shared_ptrListNode n2(new ListNode);*/cout n1.GetCount() n1.GetCount() endl;cout n2.GetCount() n2.GetCount() endl;n1-_next n2;n2-_prev n1;cout n1.GetCount() n1.GetCount() endl;cout n2.GetCount() n2.GetCount() endl;}///定制删除器 -- 可调用对象templateclass Tstruct DeleteArray{void operator()(T* ptr){cout 匿名对象DeleteArrayDate(): ptr endl;delete[] ptr;}};//std库deleter的学习/*void test_std_shared_deletor(){//template class U, class D //shared_ptr (U* p, D del); 带删除器的构造函数std::shared_ptrDate sparr1(new Date[10], DeleteArrayDate());std::shared_ptrDate sparr2(new Date[10],[](Date* ptr){cout lambda表达式 delete[]: ptr endl;delete[] ptr;});auto deleter [](Date* ptr){cout lambda表达式 delete[]: ptr endl;delete[] ptr;};std::shared_ptrDate sparr3(new Date[10], deleter);std::shared_ptrFILE spFile(fopen(Test.cpp, r),[](FILE* ptr){cout lambda表达式 delete[]: ptr endl;fclose(ptr);});}*///删除器构造函数/*templateclass Dshared_ptr(T* ptr, D del):_ptr(ptr), _pcount(new int(1)), _pmtx(new mutex), _del(del){}*/void test_ape_shared_deleter(){ ape::shared_ptrDate sp(new Date);ape::shared_ptrDate sparr1(new Date[10], DeleteArrayDate());ape::shared_ptrDate sparr2(new Date[10], [](Date* ptr) {cout lambda表达式 delete[]: ptr endl;delete[] ptr;});auto deleter [](Date* ptr){cout lambda表达式 delete[]: ptr endl;delete[] ptr;};ape::shared_ptrDate sparr3(new Date[10], deleter);ape::shared_ptrFILE spFile(fopen(Test.cpp, r),[](FILE* ptr){cout lambda表达式 delete[]: ptr endl;fclose(ptr);});}
}
7.2C11和Boost智能指针的关系
C 98 中产生了第一个智能指针auto_ptr.C boost给出了更实用的scoped_ptr/shared_ptr/weak_ptr.C TR1引入shared_ptr。[TR1不是标准版]C 11引入了unique_ptr/shared_ptr/weak_ptr。unique_ptr对应boost的scoped_ptr。[实现原理参考boost实现]