模拟实现boost库里的智能指针
来源:互联网 发布:java 文件上传过程 编辑:程序博客网 时间:2024/05/19 13:07
智能指针
什么是智能指针呢,它是行为类似于指针的类对象,但这种对象还有其他功能。我们为什么要封装智能指针类对象呢?这是因为C++中的动态内存需要用户自己来维护,动态开辟的空间,在出函数作用域或者程序正常退出前必须释放掉,否则会造成内存泄漏,所以我们会定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。
接下来我们模拟实现以下boost库里的一些智能指针了解他们的使用。Auto_ptr
第一种实现方法
#include<iostream>#include<stdlib.h>using namespace std;//模拟实现auto_ptr,非常坑爹什么情况下都不要使用template <typename T>class Auto_ptr{public: Auto_ptr(T *ptr = NULL) :_ptr(ptr) {} Auto_ptr(Auto_ptr &a)//拷贝构造函数 { _ptr = a._ptr; a._ptr = NULL;//有新的指针使用这块空间为了避免程序崩溃原先的指针 //这快空间脱离关系 } Auto_ptr & operator=(Auto_ptr& a) { if(this != &a)//防止自身赋值 { if(NULL !=_ptr) { delete _ptr; _ptr = NULL; } _ptr = a._ptr; a._ptr = NULL; } return *this; } ~Auto_ptr() { if(NULL != _ptr) { delete _ptr; _ptr = NULL; cout<<"_ptr has been deleted"; } }private: T *_ptr;};
第二种实现方法-添加bool变量
template <typename T>class Auto_ptr{public: Auto_ptr(T *ptr = NULL) :_ptr(ptr) ,Onlyone(true) { if(NULL == ptr) { Onlyone = false; } } Auto_ptr(Auto_ptr &a)//拷贝构造函数 { _ptr = a._ptr; Onlyone = true; a.Onlyone = false;//有新的指针使用这块空间为了避免程序崩溃原先管理空间的指针Onlyone置为false } Auto_ptr & operator=(Auto_ptr& a) { if(this != &a)//防止自身赋值 { if(false != Onlyone) { delete _ptr; _ptr = NULL; } _ptr = a._ptr; a.Onlyone = false; Onlyone = true; } return *this; } ~Auto_ptr() { if(true == Onlyone) { delete _ptr; _ptr = NULL; cout<<"_ptr has been deleted"; } }private: T *_ptr; bool Onlyone;};
两种方法各有优缺点,这里我们来看一下第二种的Bug.
void FunTest(){ Auto_ptr<int>ap1(new int) if(true) { Auto_ptr<int>ap2(new int) }//出了if作用域空间就会被释放,此时使用ap1指针就会出现问题}
- ScopedPtr
ScopedPtr这个智能指针采取比较暴力的手段,让空间只由自己一个来管理,我们来看看具体的实现
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<stdlib.h>using namespace std;template <typename T>class ScopedPtr{public: ScopedPtr(T *p = NULL) :_p(p) {} ~ScopedPtr() { if(NULL != _p) { delete _p; _p = NULL; } }private: //为了防止浅拷贝的问题出现,使这个类无法被拷贝和赋值 //采用的方法就是将拷贝构造函数和赋值运算符重载函数 //访问权限设为私有,并且只给出声明。 ScopedPtr(const ScopedPtr& s); T &operator=(const ScopedPtr& s);private: T *_p;};void FunTest(){ ScopedPtr<int> sp(new int); //ScopedPtr<int> sp1(sp);//错误无法完成拷贝 ScopedPtr<int> sp1(new int); //sp1 = sp;//无法成功赋值}int main(){ FunTest(); system("pause"); return 0;}
一个类如何防拷贝呢?
1.声明为私有的:这样可以通过友元函数和成员函数拷贝成成功(不可取)
2.声明为公有:可能在类外被定义(不可取)
3.声明为私有(只给出声明)(可以实现)
- SharedPtr
最后我们来模拟boost库中shared_ptr,但这个函数线程不是很安全,一般建议使用scoped_ptr
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<stdlib.h>using namespace std;//共享的智能指针//使用引用计数template <typename T>struct Delete{ void operator()(T* ptr) { if(NULL != ptr) { delete ptr; ptr = NULL; } }};struct Fclose{ void operator()(FILE* ptr) { if(NULL != ptr) { fclose(ptr); } }};template <typename T,typename _Del = Delete<T>>class SharedPtr{public: SharedPtr(T *p = NULL,_Del del = Delete<T>())//构造函数 :_p(p) ,_pCount(NULL)//不可以在此处初始化为1,如果p为NULL ,_del(del) { if(NULL != _p) { _pCount = new int(1); } } SharedPtr(const SharedPtr& sp)//拷贝构造函数 :_p(sp._p) ,_pCount(sp._pCount) { if(NULL != _pCount)//注意_pCount为NULL的情况,此时不能解引用,不用++ { ++(*_pCount); } } SharedPtr& operator=(const SharedPtr& sp) { if(_p != sp._p)//注意自身赋值,有时候两个不同的对象但里面的的指针指向 //相同不能用(this != &sp)判断出来 { if(NULL != _pCount)//被复制的对象本身为空 { if(0 == --(*_pCount))//被赋值的对象自己管理一段空间,需要释放 { Release(); } } _p = sp._p;//和其他对象共同管理 _pCount = sp._pCount; if(NULL != sp._pCount)//注意判断赋值对象是否为空 { ++(*_pCount); } } return *this; } ~SharedPtr() { Release(); }private: void Release() { if(0 == --(*_pCount)) { _del(_p); delete _pCount;//记得要释放引用计数的空间 _pCount = NULL; } }private: T *_p; int *_pCount; _Del _del;};
SharedPtr存在线程安全问题,并且也存在循环引用的问题,我们之后会详细讨论,所以建议使用ScopedPtr。
阅读全文
1 0
- 模拟实现boost库里的智能指针
- boost库的智能指针
- 智能指针的模拟实现
- 模拟实现c++标准库和boost库中的智能指针
- 模拟实现C++/boost库智能指针auto_ptr scoped_ptr和share_ptr
- 【c++】模拟实现boost库里的scoped_ptr
- Boost的智能指针
- 模拟实现智能指针
- 模拟实现智能指针
- 模拟实现智能指针
- 模拟实现智能指针
- boost库中智能指针的发展
- 浅谈BOOST库里面的智能指针
- 【干货】share智能指针的模拟实现
- 智能指针AutoPtr,ScopedPtr的模拟实现
- boost提供的智能指针
- Boost库智能指针学习
- Boost库智能指针学习
- Jtree生成虚拟结点的 增删改查操作
- USBFN Dump Packet Patchset
- android通用适配器的封装
- TCP协议和UDP协议的区别
- SQLServer中把某个表里的记录复制到另一个数据库的表中
- 模拟实现boost库里的智能指针
- kubernetes之Pod详解
- UnicodeDecodeError解决方案
- Bugly Android自动上传符号表
- Android中进程和线程的概念
- Linux 使用 dpkg 安装 Debian 包
- 库存扣多了,到底怎么整
- java中异常和检测类
- sqoop 安装与使用