• c++11之智能指针


      在c++98中,智能指针通过一个模板“auto_ptr”来实现,auto_ptr以对象的方式来管理堆分配的内存,在适当的时间(比如析构),释放所获得的内存。这种内存管理的方式只需要程序员将new操作返回的指针作为auto_ptr的初始值即可,程序员不能显式的调用delete。如 auto_ptr(new int)。

      这在一定程度上避免了堆内存忘记释放造成的问题。不过auto_ptr也有一些缺点(拷贝是返回一个左值,不能调用delete[]等),所以在c++11中被废弃了。c++11标准照中改用unique_ptr,share_ptr,及weak_ptr等智能指针自动回收堆分配的对象。

      下面是一个用c++11中智能指针实现的一个例子:

    #include <memory>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        unique_ptr<int> up1(new int(11));  //无法复制的unique_ptr
        unique_ptr<int> up2 = up1;         //不能通过编译
        
        cout << *up1 << endl;        //11
        
        unique_ptr up3 = move(up1);  //现在up3是数据唯一的unique_ptr只能指针
        
        cout << *up3 << endl;       //11
        cout << *up1 << endl;       //运行时错误
        up3.reset();                //显示释放内存
        up1.reset();                //不会导致运行时错误
        
        cout << *up3 << endl;       //运行时错误
        
        share_ptr<int> sp1(new int(22));
        share_ptr<int> sp2 = sp1;   //OK
        
        cout << *sp1 << endl;       //22
        cout << *sp2 << endl;       //22
        
        sp1.reset();
        cout << *sp2 << endl;       //22
    }

      例子使用两种不同的智能指针unique_ptr和share_ptr来自动释放堆对象的内存。在析构或者调用reset都能释放对象。

      unique_ptr与所指的对象内存绑定紧密,不能与其他的unique_ptr类型的指针共享所指对象的内存。每个unique_ptr都唯一的拥有所指对象的内存。但是这种所有权可以通过标准库的move函数来转移,如unique_ptr up3 = move(up1),一旦转移成功,原先的 unique_ptr就失去了对象内存的所有权,再使用已经失去权力的unique_ptr就会出现运行错误。

      从实现上讲,unique_ptr是删除了拷贝构造函数,保留了移动构造函数的封装类型,程序仅可以使用右值对unique_ptr进行构造,一旦构造成功,右值对象中的指针失效。

      share_ptr则不同,它允许多个该智能指针共享的永远同一堆分配对象的内存。与unique_ptr不同的是在实现上采用了引用计数,所以,一旦某个share_ptr失去了所有权,其他指针并没有影响,例子中sp1和sp2都共享指针,在sp1 reset之后只会使计数器降低,而不会导致内存的释放,当sp2 reset之后,导致引用计数器为零,share_ptr才会真正释放占有的内存空间。

      在c++11标准中,除了share_ptr和unique_ptr之外 ,还有weak_ptr。

      weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象,却并不拥有该对象。将一个weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向对象,对象还是会被释放。

      当我们创建一个weak_ptr时,要用一个shared_ptr来初始化它:

    auto p=make_shared_ptr<int>(42);
    
    weak_ptr<int> wp(p); //wp弱共享p,p的引用计数未改变

      由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock()。此函数检查weak_ptr指向的对象是否存在。使用weak_ptr的成员lock,则可返回内存中的一个share_ptr对象,并在所指向的对象无效时候,返回空。

    #include <memeroy>
    #include <iostream>
    
    using namespace std;
    
    void Check(weal_ptr<int> & wp)
    {
        share_ptr<int> sp = wp.lock();  //转换为share_ptr<int>
        if(sp != nullptr)
        {
            cout << "still" << *sp << endl;
        }
        else
        {
            cout << "pointer is invalid." << endl;
        }
    }
    
    int main()
    {
        share_ptr<int> sp1(new int(22));
        share_ptr<int> sp2 = sp1;
        weal_ptr<int> wp = sp1;//指向share_ptr<int> 所指对象
        
        cout << *sp1 << endl;  //22
        cout << *sp2 << endl;  //22
        Check(wp);             //still 22
        
        sp1.reset();
        cout << *sp2 << endl;  //22
        Check(wp);           //still 22
        
        sp2.reset();
        Check(wp);           //pointer is invalid.
        
        return 0;
    }

      例子中,sp1和sp2为共享对象,而weak_ptr指针wp也指向该内存,在sp1和sp2都有效的时候,调用weak_ptr的lock函数返回一个可用的share_ptr使用;当sp1和sp2都调用reset之后,会使堆内存的引用计数器降低为0,而一旦计数器降低为0,share_ptr就会释放内存,使之失效,此时调用weak_ptr的lock时,返回空指针nullptr。

  • 相关阅读:
    在SQL Server中使用NewID()随机取得某行
    委托和事件:第 3 页 事件的由来
    case when then else 详解
    spring-boot-starter-security Spring Boot中集成Spring Security
    spring-boot-actuator健康监控
    汉字转拼音开源工具包Jpinyin介绍
    JAVA实现汉字转换为拼音 pinyin4j/JPinyin
    Spring MVC 后端接口支持跨域CORS调用
    web开发-CORS支持
    maven POM.xml 标签详解
  • 原文地址:https://www.cnblogs.com/ChinaHook/p/5550809.html
Copyright © 2020-2023  润新知