必须要注意的 C++ 动态内存资源管理(二)——指针对象简单实现
必须要注意的 C++动态内存资源管理(二)——指针对象简单实现 四.拷贝类型的资源
上节我们说过,对于图片类型的资源我们有时候往往采用拷贝(如果对于那种公共图片,可能采用唯一副本,提供地址使用)。这样情况,我们就需要在拷贝构造函数,以及拷贝赋值函数里面对源地址的内容(对象)进行拷贝。而在析构函数里面要释放自身所占有的资源。 template<typename T>
class res_ptr
{
public:
typedef res_ptr<T> _myType;
friend void swap(_myType& _Lhs, _myType& _Rhs){
std::swap(_Lhs.pointer, _Rhs.pointer); }
res_ptr(T* p = nullptr) :pointer(p){ }
res_ptr(const _myType& _Al) :pointer(new T(*_Al.pointer)){ }
~res_ptr(){ delete pointer; }
_myType& operator=(const _myType& _Rhs){
delete pointer; pointer = new _myType(*_Rhs.pointer); return *this;
}
T& operator*(){ return *pointer; }
private:
T* pointer;
}; 对于这种类型的对象,当赋值的时候,就会产生多个资源副本。赋值之后,源对象和新对象就没有什么关系了。因为各自是操作的自身占有的资源副本。 五.控制权转移类型的资源
如果了解过操作系统的,我们都知道有一类资源叫做临界资源,也就是只能同时被一个进程使用的资源。这里也是一样对于某些类如:设备(IO),文件的资源;这样的资源不能够进行拷贝,只能进行支配权的转移。 template<typename T>
class res_ptr
{
public:
typedef res_ptr<T> _myType;
friend void swap(_myType& _Lhs, _myType& _Rhs){
std::swap(_Lhs.pointer, _Rhs.pointer); }
res_ptr(T* p = nullptr) :pointer(p){ }
res_ptr( _myType& _Al) :pointer(_Al.pointer){
_Al.pointer = nullptr;
}
~res_ptr(){ delete pointer; }
_myType& operator=(_myType& _Rhs){
delete pointer; pointer = _Rhs.pointer;
_Rhs.pointer = nullptr; return *this;
}
T& operator*(){ return *pointer; }
private:
T* pointer;
}; 对于这种类型的对象,当赋值的时候,就会产生多个资源副本。经过赋值,新对象获取资源之后,源对象就失去了对资源的支配权利。可能在这使用拷贝(赋值)这样的方式来表示支配权的转移不太合理,不过这里只是举个例子。 六.引用计数类型的资源
还有一类资源,类似于数据库连接,网络sokets这样的可以共享的资源。从资源被创建开始可以被多个地方所”引用”,但是实际上的资源备份只有一个副本。当其中一个”引用”销毁了并一定会释放内存,只有当所有”引用”都失效(也就是这份资源没有使用者)的时候才会释放内存。在实现方法上,就需要多添加一个变量用来记录引用次数。 template<typename T>
class res_ptr
{
public:
typedef res_ptr<T> _myType;
friend void swap(res_ptr<T>& _Lhs, res_ptr<T>& _Rhs){
std::swap(_Lhs.use, _Rhs.use);
std::swap(_Lhs.pointer, _Rhs.pointer);
}
res_ptr(T* p = nullptr) :pointer(p), use(new std::size_t()){ }
res_ptr(const _myType& _Al) :pointer(_Al.pointer), use(_Al.use){ ++*use; } ~res_ptr(){
free();
}
_myType& operator=(const _myType& _Rhs){
++*_Rhs.use; free();
pointer = _Rhs.pointer; use = _Rhs.use;
return *this;
}
T& operator*(){ return *pointer; }
std::size_t user(){ return *use; }
private:
void free(){ if (--*use == ){ delete pointer; delete use; printf("析构\n"); } }
T* pointer;
std::size_t *use;
}; 通过添加引用次数来判断资源的最后一个使用者,因为在使用者创建和销毁的时候要对该资源的所有使用者的计数器都要更新,所以计数器我们要使用指针,这样大家记录地址,一个更新大家都更新了。提供了user()方法可以查看该资源有多少使用者。 下一节我们来介绍C++11中的智能指针 :shared_ptr , unique_ptr , weap_ptr
必须要注意的 C++ 动态内存资源管理(二)——指针对象简单实现的更多相关文章
- 必须要注意的 C++ 动态内存资源管理(六)——vector的简单实现
必须要注意的 C++ 动态内存资源管理(六)——vector的简单实现 十六.myVector分析 我们知道,vector类将其元素存放在连续的内存中.为了获得可接受的性能,vetor ...
- 必须要注意的 C++ 动态内存资源管理(一)——视资源为对象
必须要注意的 C++ 动态内存资源管理(一)——视资源为对象 一.前言 所谓资源就是,一旦你用了它,将来必须还给系统.如果不这样,糟糕的事情就会发生.C++ 程序中最常见使用的资源就是 ...
- 必须要注意的 C++ 动态内存资源管理(五)——智能指针陷阱
必须要注意的 C++ 动态内存资源管理(五)——智能指针陷阱 十三.小心使用智能指针. 在前面几节已经很详细了介绍了智能指针适用方式.看起来,似乎智能指针很强大,能够很方便很安全的管理 ...
- 【足迹C++primer】39、动态内存与智能指针(3)
动态内存与智能指针(3) /** * 功能:动态内存与智能指针 * 时间:2014年7月8日15:33:58 * 作者:cutter_point */ #include<iostream> ...
- 12.动态内存和智能指针、 直接管理内存、shared_ptr和new结合使用
12.动态内存和智能指针 1.智能指针分为两种shared_ptr和unique_ptr,后者独占所指向的对象.智能指针也是模板,使用时要用尖括号指明指向的类型.类似emplace成员,make_sh ...
- 【C++】动态内存与智能指针
C++常见的内存分配方式有三种: 从静态存储区分配,这里主要是存储局部static对象,类的static成员以及定义在函数之外的变量: 从栈内存分配,这里主要是存储函数内的非static对象: 从堆内 ...
- C++相关:动态内存和智能指针
前言 在C++中,动态内存的管理是通过运算符new和delete来完成的.但使用动态内存很容易出现问题,因为确保在正确的时间释放内存是及其困难的.有时候我们会忘记内存的的释放,这种情况下就会产生内存泄 ...
- c++学习笔记—动态内存与智能指针浅析
我们的程序使用内存包含以下几种: 静态内存用来保存局部static对象.类static数据成员以及定义在任何函数之外的变量,在使用之前分配,在程序结束时销毁. 栈内存用来保存定义在函数内部的非stat ...
- C++——动态内存分配2-创建对象数组
//创建对象数组 #include<iostream> using namespace std; class Point { public: Point() { ...
随机推荐
- JSON.stringify(),JSON.parse(),toJSON()使用方法总结
今天在看<你不知道的javascript-中>第四章‘强制类型转换’的时候,发现JSON.stringify(),JSON.parse(),toJSON()有很多细节,自己也就总结测试了一 ...
- W3C--BOM(1)知识梳理
<一>BOM浏览器对象模型 1. window 1.1 window.innerHeight浏览器窗口的内部高度,window.innerWidth浏览器窗口的内部宽度 (对于Inter ...
- BZOJ1485: [HNOI2009]有趣的数列(卡特兰数+快速幂)
题目链接 传送门 题面 思路 打表可以发现前六项分别为1,2,5,12,42,132,加上\(n=0\)时的1构成了卡特兰数的前几项. 看别人的题解说把每一个数扫一遍,奇数项当成入栈,偶数项当成出栈, ...
- 深度学习Keras框架笔记之Activation类使用
使用 keras.layers.core.Activation(activation) Apply an activation function tothe input.(貌似是把激活函数应用到输入数 ...
- 独角兽估值30亿美金,我们聊聊RPA是什么
https://www.jianshu.com/p/397ecd238ffc 缩短法定工作时间,已成国际劳动立法趋势,全球政府都曾面对这样的议题,过往企业IT也在思考这件事,开发出更好的软件系统帮助员 ...
- 趣味编程:FizzBuzz(Haskell版)
g :: Int -> Int -> Int -> String g n 0 0 = "FizzBuzz" g n 0 _ = "Fizz" ...
- [51 Nod 1584] 加权约数和
题意 求∑i=1N∑j=1Nmax(i,j)⋅σ1(ij)\large \sum_{i=1}^N\sum_{j=1}^Nmax(i,j)\cdot\sigma_1(ij)i=1∑Nj=1∑Nmax ...
- docker容器中oracle数据库导出dmp文件
Oracle数据库安装在docker容器中 1首先查看容器 docker ps 2进入oracle容器 docker exec -it 7f0f3f2d4f88 /bin/bash 3导出整个库:这个 ...
- 学习Spring-Data-Jpa(十四)---自定义Repository
有些时候,我们需要自定义Repository实现一些特殊的业务场景. 1.自定义单个Repository 1.1.首先提供一个片段接口和实现(接口的实现默认要使用Impl为后缀,实现本身不依赖spri ...
- 注册服务到etcd中
如上存放一些服务的key到etcd中,商品有两个,主要是为了负载均衡的key func NewService() *Service { config := clientv3.Config{ Endpo ...