zoukankan      html  css  js  c++  java
  • C++内存管理之unique_ptr

      一个unique_ptr"拥有“他所指向的对象。与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定的对象。当unique_ptr被销毁时,它所指向的对象也被销毁。uniptr_ptr表达的是一种独占的思想。

     

    初始化

    #include <iostream>
    #include <memory>
    using namespace std;
    
    //常规操作
    int main(int argc, char *argv[])
    {
        unique_ptr<double> p1;               //!可指向一个double的unique_ptr
        unique_ptr<int> p2(new int(56));     //!p2指向了一个值为42的int
    
        unique_ptr<string> pstr(new string("strtest"));
    //    unique_ptr<string> pstrCopy(pstr); //!error: 不支持对象的拷贝
        unique_ptr<string> pstrAssin;
    //    pstrAssin = pstr                   //!error: uniptr不支持赋值
        return 0;
    }

    unique_ptr一般操作

      关于unique_ptr还支持哪些操作,在前面的博文中我也做了总结,请参考该篇文章中图表:https://www.cnblogs.com/wangkeqin/p/9351191.html

     unique_ptr所有权转移

      虽然我们不能拷贝赋值unique_ptr,但是可以通过调用release或者set将指针的所有权从一个(非const)unique_ptr转移给一个unique:

    #include <iostream>
    #include <memory>
    
    
    using namespace std;
    
    class TEST
    {
    public:
        TEST(const string & name)
            :_name(name)
        {cout<<"TEST:"<<_name<<endl;}
        TEST(const TEST & another)
        {   _name = another._name;
            cout<<another._name<<" copyStruct "<<_name<<endl;}
        TEST & operator =(const TEST & another){
            if(&another==this)
                return *this;
            this->_name=another._name;
            cout<<another._name<<" copyAssin to "<<_name<<endl;
        }
        ~TEST(){cout<<"~TEST:"<<_name<<endl;}
    
    //private:
        string _name;
    };
    
    //其他操作
    int main()
    {
        unique_ptr<TEST> p1(new TEST("case_1"));
        unique_ptr<TEST> p2(p1.release());          //!将所有权从p1转移到p2,p1现在指向NULL。
        cout<<"++++++++++++++++++++++++"<<endl;
        unique_ptr<TEST> p3(new TEST("case_2"));
        p2.reset(p3.release());                     //!p2释放了原来指向的内存,接受了p3指向的内存。
        getchar();
    }

    传递unique_ptr参数和返回unique_ptr

      不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或者赋值一个将要被销毁的unique_ptr。其本质就是调用了移动拷贝和移动赋值;最常见的例子是从函数返回一个unique_ptr:

    #include <iostream>
    #include <memory>
    
    
    using namespace std;
    
    class TEST
    {
    public:
        TEST(const string & name)
            :_name(name)
        {cout<<"TEST:"<<_name<<endl;}
        TEST(const TEST & another)
        {   _name = another._name;
            cout<<another._name<<" copyStruct "<<_name<<endl;}
        TEST & operator =(const TEST & another){
            if(&another==this)
                return *this;
            this->_name=another._name;
            cout<<another._name<<" copyAssin to "<<_name<<endl;
        }
        ~TEST(){cout<<"~TEST:"<<_name<<endl;}
    
    //private:
        string _name;
    };
    
    
    //!例外:
    //①返回一个即将被销毁的uniptr
    unique_ptr<TEST> retDying(string param)
    {
        return unique_ptr<TEST>(new TEST(param));
    }
    
    //②返回一个局部对象;
    unique_ptr<TEST> retTemp(string param)
    {
        unique_ptr<TEST> pTemp(new TEST(param));
        return pTemp;
    }
    
    int main()
    {
        unique_ptr<TEST>ret1 = retDying("dying");
        cout<<(*ret1)._name<<endl;
    
        unique_ptr<TEST>ret2 = retTemp("temp");
        cout<<(*ret2)._name<<endl;
        getchar();
    }

    向后兼容:auto_ptr

      标准库较早的版本包含了一个名为auto_ptr的类,它具有unique_ptr的部分特性,但不是全部。特别时我们在容器中保存auto_ptr,也不能从函数中返回auto_ptr。虽然auto_ptr仍然是标准库的一部分,但是编写程序时应该使用unique_ptr。

    向unique_ptr传递删除器

      类似于shared_ptr,unique_ptr默认情况下也是使用delete释放它指向的对象。与shared_ptr一样,我们可以重载一个unique_ptr中默认的删除器。但是unique_ptr管理删除器的方式与shared_ptr不同,其原因我们将在后面继续补充。

      重载一个unique_ptr中的删除器会影响到unique_ptr类型如何构造(或reset)该类型的对象。与重载关联器的比较操作类似。我们必须在尖括号中unique_ptr指向类型之后提供删除器类型。在创建或者reset一个这种unique_ptr这种类型的对象时,必须提供一个指定类型的可调用对象:

    #include <stdio.h>
    #include <memory>
    using namespace std;
    
    void closePf(FILE * pf)
    {
        cout<<"----close pf after works!----"<<endl;
        fclose(pf);
        cout<<"*****end working****"<<endl;
    }
    
    int main()
    {
        //    FILE * fp2 = fopen("bin2.txt", "w");
        //    if(!pf)
        //        return -1;
        //    char *buf = "abcdefg";
        //    fwrite(buf, 8, 1, fp2);
        //    fclose(fp2);
        //______________________________________
        //    shared_ptr<FILE> pf(fopen("bin2.txt", "w"),closePf);
        //    cout<<"*****start working****"<<endl;
        //    if(!pf)
        //        return -1;
        //    char *buf = "abcdefg";
        //    fwrite(buf, 8, 1, pf.get());    //!确保fwrite不会删除指针的情况下,可以将shared_ptr内置指针取出来。
        //    cout<<"----write int file!-----"<<endl;
    
        unique_ptr<FILE,decltype(closePf)*> pf(fopen("bin2.txt", "w"),closePf); //!使用了decltype类型推断
        cout<<"*****start working****"<<endl;
        if(!pf)
            return -1;
        char *buf = "abcdefg";
        fwrite(buf, 8, 1, pf.get());                            //!确保fwrite不会删除指针的情况下,可以将unique_ptr内置指针取出来。
        cout<<"----write int file!-----"<<endl;
        return 0;
    }

    使用unique_ptr管理动态数组

      标准库提供了一个可以管理new分配动态数组的unique_ptr版本。为了用用一个unique_ptr管理动态数组,我们必须在对象类型后面跟一对空方括号;如此,在unique对象销毁的时候,也可以自动调用delete[ ]而非delete来完成内存的释放。

    #include <iostream>
    #include <memory>
    using namespace std;
    
    class ArrTest
    {
    public:
        ArrTest(){
            static int i = 0;
            _i = i;
            cout<<" ArrTest()"<<":"<<i++<<endl;
        }
        ~ArrTest(){
            static int i = 0;
            cout<<"~ ArrTest()"<<":"<<i++<<endl;
        }
        int _i;
    };
    
    int main()
    {
        unique_ptr<ArrTest[]> p(new ArrTest[10]);
        cout<<p[4]._i<<endl;    //!获取某个元素值,警告:不要使用越界的下标,unique_ptr也是不检查越界的。
        p.reset();
        return 0;
    }

  • 相关阅读:
    zoj 3279 线段树 OR 树状数组
    fzu 1962 树状数组 OR 线段树
    hdu 5057 块状链表
    hdu3487 Play with Chain
    bzoj 1588营业额统计(HNOI 2002)
    poj2823 Sliding Window
    poj2828 Buy Tickets
    poj2395 Out of Hay
    poj3667 Hotel
    poj1703 Lost Cows
  • 原文地址:https://www.cnblogs.com/wangkeqin/p/9383658.html
Copyright © 2011-2022 走看看