手机微网站尺寸,码迷seo,郑州网站建设与设计,wordpress mp4 插件下载一、智能指针简介 智能指针是一个类似于指针的类#xff0c;将指针交给这个类对象进行管理#xff0c;我们就可以像使用指针一样使用这个类#xff0c;并且它会自动释放资源。 智能指针运用了 RAII 的思想(资源获得即初始化)。RAII 是指#xff0c;用对象的生命周期来管理资…一、智能指针简介 智能指针是一个类似于指针的类将指针交给这个类对象进行管理我们就可以像使用指针一样使用这个类并且它会自动释放资源。 智能指针运用了 RAII 的思想(资源获得即初始化)。RAII 是指用对象的生命周期来管理资源类对象创建时拿到资源析构时释放资源。
RAII 优点 1、不需要显式释放资源。 2、在对象生命周期内资源始终都是有效的。
简单的智能指针的示例
templateclass T
class SmartPtr
{
public:SmartPtr(T* ptr):_ptr(ptr){}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}// 析构时释放资源~SmartPtr(){cout 释放资源\n;if (_ptr)delete _ptr;}private:T* _ptr;
}; void func()
{int* p1 new int[10];int* p2 new int[10];int* p3 new int[10];delete[] p1;delete[] p2;delete[] p3;
} 在上述代码中指针 p1, p2, p3 在创建时都有可能出现异常如果在 p1 创建时出现异常那么我们只需要捕获如果在 p2 创建时出现异常那么我们除了捕获异常还需要释放 p1而如果在 p3 创建时出现异常那么我们又要释放 p1 和 p2。 要写多个 try catch这会让我们的代码变得十分复杂并且可能会有遗漏造成内存泄漏。 这时智能指针的优势就体现出来了只需要把指针交给智能指针进行管理就能够在生命周期结束时自动释放。
用上面的简单的智能指针示例
void func()
{SmartPtrint sp1(new int[10]);SmartPtrint sp2(new int[10]);SmartPtrint sp3(new int[10]);
} 在对象的生命周期结束后会自动调用析构释放资源。我们就不需要写复杂的代码也不用担心内存泄漏的问题了。
二、智能指针的拷贝问题 智能指针的拷贝如果不写的话默认生成的是浅拷贝。而浅拷贝会使同一份资源释放两次运行会报错。
void func()
{SmartPtrint sp1(new int[10]);SmartPtrint sp2(sp1);
} 这时候就有多种解决方案 1、auto_ptr 将资源全部转给一方将另一方置为空。(不靠谱现在禁止使用了) 2、unique_ptr 拷贝有问题干脆禁止拷贝。将拷贝封住就可以了。(不需要拷贝的场景)
unique_ptr 的简单实现
templateclass T
class Unique_Ptr
{
public:Unique_Ptr(T* ptr):_ptr(ptr){}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}// 析构时释放资源~Unique_Ptr(){cout 释放资源\n;if (_ptr)delete _ptr;}Unique_Ptr(const Unique_PtrT up) delete;Unique_PtrT operator(const Unique_PtrT up) delete;
private:T* _ptr;
};
3、shared_ptr 通过引用计数解决多次析构问题 用一个引用计数表示当前共有多少对象在使用该指针每次析构都减引用计数当引用计数减到0就释放资源。 为什么引用计数不能为 int 和 静态 static int int如果引用计数是 int 当我们改了一个引用计数其他的对象无法同步。 如有三个对象 sp1, sp2, sp3如果sp3拷贝sp2无法告知sp1sp1 无法同步引用计数。 static int如果用静态的整个类共用一个引用计数无法区分shared_ptr 管理的多个指针的引用计数。 如sp1(new int(1)); sp2(new int(2)); sp1 和 sp2 的引用计数肯定是不同的但用静态无法区分因为它是整个类共有的。
因此引用计数用指针或引用最佳。
shared_ptr 简单实现代码
templateclass T
class Shared_Ptr
{
public:// 引用计数初始为 1Shared_Ptr(T* ptr):_ptr(ptr),_count(new int(1)){}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}// 返回引用计数int use_count(){return *_count;}Shared_Ptr(const Shared_PtrT sp){// 将资源拷贝过来并 引用计数_ptr sp._ptr;_count sp._count;(*_count);}Shared_PtrT operator(const Shared_PtrT sp){// 防自己给自己赋值if (sp._ptr ! _ptr){// 赋值会将原本的资源覆盖因此要进行判断// 如果是最后一个对象就析构释放不是就 减减当前计数if (--(*_count) 0){delete _ptr;delete _count;}// 拷贝资源拷贝的计数_ptr sp._ptr;_count sp._count;(*_count);}return *this;}// 析构时释放资源~Shared_Ptr(){// 当引用计数减到 0就释放资源if (--(*_count) 0){cout 释放资源\n;delete _ptr;delete _count;}else{// 打印调试cout 减减引用计数当前引用计数为: *_count endl;}}
private:T* _ptr; // 指针int* _count; // 引用计数
}; 上述代码中存在线程安全问题引用计数需要加锁保护
多线程测试代码 测试记得把打印的调试信息注释掉
// 测试线程安全拷贝 n 个对象
// 测试记得把打印的调试信息注释掉
void ThreadRoute(Shared_Ptrint sp, int n, mutex mtx)
{for (int i 0; i n; i){Shared_Ptrint test(sp);}
}void TestSharedThreadSafe()
{Shared_Ptrint sp(new int(1));mutex mtx;int n 10000;// 因为不清楚内部实现多线程的引用要使用库函数 refthread t1(ThreadRoute, ref(sp), n, ref(mtx));thread t2(ThreadRoute, ref(sp), n, ref(mtx));t1.join();t2.join();} 多线程版 shared_ptr 实现在修改引用计数时加锁保护
// 多线程
templateclass T
class Shared_Ptr
{
public:// 引用计数初始为 1Shared_Ptr(T* ptr):_ptr(ptr), _count(new int(1)), _pmtx(new mutex){}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}void AddCount(){// 对公共资源 引用计数加加加锁保护unique_lockmutex lock(*_pmtx);(*_count);}void DelCount(){// 对公共资源 引用计数减减加锁保护unique_lockmutex lock(*_pmtx);--(*_count);}// 返回管理的指针T* Get(){return _ptr;}// 返回引用计数 int use_count(){return *_count;}// 拷贝构造Shared_Ptr(const Shared_PtrT sp){// 将资源拷贝过来并 引用计数_ptr sp._ptr;_count sp._count;_pmtx sp._pmtx;// 将锁拿到后再 用锁保护引用计数AddCount();}Shared_PtrT operator(const Shared_PtrT sp){// 防自己给自己赋值if (sp._ptr ! _ptr){// 释放原本资源release();// 拷贝资源拷贝的计数_pmtx sp._pmtx;_ptr sp._ptr;_count sp._count;AddCount();}return *this;}// 释放资源void release(){unique_lockmutex lock(*_pmtx);// 当引用计数减到 0就释放资源if (--(*_count) 0){// cout 释放资源\n;// 释放锁之前 解锁lock.unlock();delete _ptr;delete _count;delete _pmtx;}else{// 打印调试// cout 减减引用计数当前引用计数为: *_count endl;}}// 析构时释放资源~Shared_Ptr(){release();}
private:T* _ptr; // 指针int* _count; // 引用计数mutex* _pmtx; // 锁
};
三、shared_ptr 的循环引用问题 当存在类里面有智能指针互相指向时就会出现循环引用问题。 因此官方给 shared_ptr 配了一个小弟weak_ptr weak_ptr 不是常规的智能指针它具有以下特点 它不支持 RAII 支持像指针一样使用 专门设计出来解决循环引用问题 核心weak_ptr 支持用 shared_ptr 构造它不会加加引用计数。 测试循环引用的代码
struct ListNode
{// 双向链表Shared_PtrListNode _prev;Shared_PtrListNode _next;// 析构~ListNode(){cout 释放节点\n;}
};void CirculaReferenceProblem()
{Shared_PtrListNode n1(new ListNode);Shared_PtrListNode n2(new ListNode);n1-_next n2;n2-_prev n1;
} weak_ptr 的简单实现
templateclass T
class Weak_Ptr
{
public:Weak_Ptr():_ptr(nullptr){}Weak_Ptr(const Shared_PtrT sp):_ptr(sp.Get()){}Weak_PtrT operator(const Shared_PtrT sp){_ptr sp.Get();return *this;}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}
private:T* _ptr;
}; 解决方案在内部的互相引用处用 weak_ptr 就可以了
struct ListNode
{// 在内部的互相引用处用 weak_ptr 就可以了Weak_PtrListNode _prev;Weak_PtrListNode _next;~ListNode(){cout 释放节点\n;}
};void CirculaReferenceProblem()
{Shared_PtrListNode n1(new ListNode);Shared_PtrListNode n2(new ListNode);n1-_next n2;n2-_prev n1;
}
四、定制删除器 有的时候我们使用 new [] 开辟空间或传入的是文件指针就可以定制删除器来指定使用 delete [] 或fclose() 删除。 定制删除器就是传入一个可调用对象(仿函数或lambda或函数指针)在释放时调用。 改变 1、成员加一个 function 包装的删除器构造函数添加删除器模版 2、release() 中删除改为用定制删除器删除
添加定制删除器
templateclass T
class Shared_Ptr
{
public:Shared_Ptr():_ptr(nullptr), _count(new int(1)), _pmtx(new mutex){}// 引用计数初始为 1Shared_Ptr(T* ptr):_ptr(ptr), _count(new int(1)), _pmtx(new mutex){}// 定制删除器templateclass DShared_Ptr(T* ptr, D del):_ptr(ptr), _count(new int(1)), _pmtx(new mutex), _del(del){}// 像指针一样使用重载 * 和 -T operator*(){return *_ptr;}T* operator-(){return _ptr;}void AddCount(){// 对公共资源 引用计数加加加锁保护unique_lockmutex lock(*_pmtx);(*_count);}void DelCount(){// 对公共资源 引用计数减减加锁保护unique_lockmutex lock(*_pmtx);--(*_count);}// 返回管理的指针T* Get() const{return _ptr;}// 返回引用计数 int use_count(){return *_count;}// 拷贝构造Shared_Ptr(const Shared_PtrT sp){// 将资源拷贝过来并 引用计数_ptr sp._ptr;_count sp._count;_pmtx sp._pmtx;// 将锁拿到后再 用锁保护引用计数AddCount();}Shared_PtrT operator(const Shared_PtrT sp){// 防自己给自己赋值if (sp._ptr ! _ptr){// 释放原本资源release();// 拷贝资源拷贝的计数_pmtx sp._pmtx;_ptr sp._ptr;_count sp._count;AddCount();}return *this;}// 释放资源void release(){unique_lockmutex lock(*_pmtx);// 当引用计数减到 0就释放资源if (--(*_count) 0){// cout 释放资源\n;// 释放锁之前 解锁lock.unlock();// delete _ptr;// 改为用定制删除器删除_del(_ptr);delete _count;delete _pmtx;}else{// 打印调试// cout 减减引用计数当前引用计数为: *_count endl;}}// 析构时释放资源~Shared_Ptr(){release();}
private:T* _ptr; // 指针int* _count; // 引用计数mutex* _pmtx; // 锁functionvoid(T*) _del [](T* ptr) {cout 默认 delete\n;delete ptr;};
}; 测试代码
templateclass T
struct DeleteArr
{void operator()(T* ptr){cout delete[] ptr;delete[] ptr;}
};void TestDeletor()
{// 如果不传定制删除器运行会报错Shared_PtrListNode sp(new ListNode[10], DeleteArrListNode());
} 到此结束感谢大家观看♪(ω)