effective c++-资源管理

条款13:以对象管理资源

(一)使用RAII

a) 使用RAIIresource acquisition is initialization)(资源获取时机就是初始化时机),即在构造函数中获取资源,在析构函数中释放资源。自己编写资源管理类时,要加上引用计数,引用计数不为0时,不能释放对象,不加引用计数在多线程下会产生析构的竞态。

(二)C++ RAII应用实例:用于管理资源的三个智能指针(其实是三个类模板)

a) auto_ptrunique_ptr

i. 使用:auto_ptr<ClassName> ptr(new ClassName());

ii. 在构造ptr时,在其构造函数中获取资源className的对象(放在堆上)

iii. 在超出ptr范围时,在其析构函数中调用delete销毁堆上的对象

iv. 【存在问题】:复制存在问题,再次定义一个auto_ptr<ClassName> ptr2(ptr),那么前一个ptr会指向NULL,即auto_ptr不允许存在一个以上的auto_ptr指向同一个对象。

b) shared_ptr控制对象的生命期

i. 和普通指针一样,通过【(*ptr).对象方法】或【ptr->对象方法】来访问对象的成员变量和成员函数。

ii. auto_ptr相似也是c++ RAII的应用实例,用来管理资源。不同的是shared_ptr拥有一个引用计数,它不存在auto_ptr存在的问题,即shared_ptr复制动作是正常的,它允许多个shared_ptr指向同一个对象,并且在引用计数为0的时候,调用自己的析构函数,释放获取的资源。(只要有一个shared_ptr指向对象,对象就不会被释放掉

iii. 但它存在,引用计数的循环引用问题

1. 引用计数的循环引用问题

1. class Woman;    

2. class Man{  

3.     std::shared_ptr _wife; 

4. public:    

5.     void setWife(std::shared_ptr woman){    

6.         _wife = woman;    

7.     } 

8.     void doSomthing(){    

9.         if(_wife.lock()){}    

10.     }  

11.     ~Man(){  std::cout << "kill man\n"; }    

12. }; 

13. class Woman{    

14.     std::shared_ptr _husband;    

15. public:    

16.     void setHusband(std::shared_ptr man){    

17.         _husband = man;    

18.     }    

19.     ~Woman(){ std::cout <<"kill woman\n"; }    

20. };  

21. int main(int argc, char** argv){    

22.     std::shared_ptr m(new Man());std::shared_ptr w(new Woman());

23.     m->setWife(w);w->setHusband(m);    

24. }    

相互引用,由于shared_ptr管理对象生命周期,所以,都不能正常释放掉husband的生命期由wife的生命期决定,wife的生命期由husband的生命期决定。

2. 解决方案

a) womanman中的其中一个shared_ptr 改成weak_ptr就行

c) weak_ptr不控制对象的生命期

i. 不控制对象的生命期,但是知道对象仍然活着

ii. weak_ptrshared_ptr搭配不会出现引用循环的情况。Weak_ptr本身不能访问对象。weak_ptr.lock()方法返回了:1.若对象为空,返回NULLshared_ptr2.若对象非空返回非NULLshared_ptr,然后又shared_ptr来操作对象。

 

 

条款14:在资源管理类中小心copying行为

(一)RAII对象的复制与问题引出

a) 复制RAII对象时,可以选择一并复制RAII管理的资源,也可以选择不产生所管理资源的副本。

b) RAII类管理mutexmutex锁住,不希望复制资源mutex

Class MRAII{
Mutex *mutexptr;
Public:
MRAII(Mutex* ptr):mutexptr(ptr){
Lock(mutexptr);
}
~MRAII(){
~lock(mutexptr);
}
};
Mutex m;//定义互斥量
MRAII m1(&m);//锁住互斥量
MRAII m2(m1);//复制管理类

这样两个mutex指针都指向了mutex对象。一个指针如果释放掉锁,另一个就成了指向不明。

(二)解决方案

a) 禁止复制,将复制构造函数和赋值运算私有化。

b) 将原生指针mutex*替换成shared_ptr,防止上述现象产生,另外shared_ptr的引用计数为0时,会删除资源对象m,这是不愿意见到的,所以需要重新指定shared_ptr的删除器

c) 深拷贝,复制原生指针mutex*所指的对象

d) 使用auto_ptr,转移资源的拥有权

条款15:在资源管理类中提供对原始资源的访问

(一)RAII类是为了防止资源泄漏,不是为了封装资源。

(二)存在直接访问原生资源的情况

a) 显式转换,shared_ptrauto_ptr都具有get方法,返回原生资源

b) 隐式转换,【ptr->被管理对象的方法】或者【(*ptr).被管理对象的方法】

条款16:成对使用new和delete时要采用相同形式

(一)Newdelete配套,new[]delete[]配套

(二)New:申请一块内存,调用构造函数构造一个对象;delete:析构一个对象,然后释放一块内存。New[]:申请一块内存,构造一组对象(对象数组);delete[]:析构一组对象,然后释放这块内存。所以newdelete[]不能串用;new[]delete也不能串用。

条款17:以独立语句将newed对象置入智能指针

就是:Shared_ptr<ClassName> ptr(new ClassName());

解释:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值