[C++] 智能指针与循环引用

   1、智能指针的出现

      在我们写程序的时候总会遇到一些需要new的问题,在没有智能指针的时候,我们只能收到的去delete,一旦我们忘记就会出现内存泄漏的问题。智能指针的出现就是为了解决这一问题,让我们new的对象,能够在使用完毕之后自己delete,而不用我们手动delete。

   2、智能指针的历史

        1、auto_ptr(C++98)

2、unique_ptr(C++11)

3、shared_ptr(C++11)

4、weak_ptr(C++11)

   auto_ptr在C++98中提出在C++11中已经被抛弃,就不再叙述。

   3、智能指针实现原理

     智能指针是一种资源管理类,通过对原始指针进行封装,在资源管理对象进行析构时对指针指向的内存进行释放;通常使用引用计数方式进行管理。在指针进行拷贝的时候计数器会加1,而对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(减1,如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数(加1)。

  实现简单的智能指针:

class Counter
{
 friend class SmartPointer;
public:
 Counter()
 {
  ptr = NULL;
  cnt = 0;
 }
 Counter(Object* p)
 {
  ptr = p;
  cnt = 1;
 }
 ~Counter()
 {
  delete ptr;
 }
private:
 Object* ptr;
 int cnt;
};

class SmartPointer
{
public:
 SmartPointer(Object* p)
 {
  ptr_counter = new Counter(p);
 }
 SmartPointer(const SmartPointer &sp)
 {
  ptr_counter = sp.ptr_counter;
  ++ptr_count->cnt;
 }
 SmartPointer& operator=(const SmartPointer &sp)
 {
  ++sp.ptr_counter->cnt;
  --ptr_counter->cnt;
  if (ptr_counter->cnt == 0)
  {
   delete ptr_counter;
  }
  ptr_counter = sp.ptr_counter;
 }
 ~SmartPointer()
 {
  - -ptr_counter->cnt;
  if (ptr_counter->cnt == 0)
  {
   delete ptr_counter;
  }
 }
private:
 Counter* ptr_counter;

}; 
     4.1 unique_ptr

      当我们定义一个unique_ptr的时候,需要将其绑定到一个new返回的指针。

      只能有一个uniqu_ptr指向对象,也就是说它不能被拷贝,也不支持赋值,但是我们可以通过move来移动。

      

unique_ptr<string> p3 (new string ("test");  
unique_ptr<string> p4;                      
p4 = p3;    
    上述代码是错误的。但是如说使用auto_ptr就是没有问题的

auto_ptr<string> p1(new string ("test") ;
auto_ptr<string> p2;                       
p2 = p1;    

  当我们使用auto_ptr时,可以有效的防止p2,p1指向同一对象,但是因为p2现在指向字符串,剥夺了了p1的权利,如此p1就不会指向任何对象,但是如果我们再使用p1的话,就会出现未知错误!使用unipue_ptr就可以很好的避免这一点,并且C++有一个标准库函数std::move(),让你能够将一个unique_ptr赋给另一个,使用move后,原来的指针仍转让所有权变成空指针,可以对其重新赋值。

unique_ptr<string> ps1, ps2;
ps1 = new string("test");
ps2 = move(ps1);
ps1 = new string("ok");
cout << *ps2 << *ps1 << endl;
  而且,程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做
  
unique_ptr<string> test(const char * str)
{
    unique_ptr<string> temp (new string (str)); 
    return temp;
}
unique_ptr<string> ps;
ps = demo('test");

    4.2shared_ptr

 采用引用计数的智能指针。 shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作.

  4.3weak_ptr

  weak_ptr 提供对一个或多个 shared_ptr 实例所属对象的访问,但是,不参与引用计数。

    5、循环引用

    循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用。

    即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是在B析构后才析构A,这就是循环引用问题,违反常规,导致内存泄露。

   解决循环引用方法:

   1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
   2. 当A的生存期超过B的生存期的时候,B改为使用一个普通指针指向A。
   3. 使用weak_ptr打破这种循环引用,因为weak_ptr不会修改计数器的大小,所以就不会产生两个对象互相使用一个shared_ptr成员变量指向对方的问题,从而不会引起引用循环。

   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值