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;
    }
    复制代码

    ————雁过留痕,风过留声,人的记忆是一种很不靠谱的东西。记下这些笔记,希望自己能够在需要的时候有所回忆,也希望能够帮助哪些需要获取这些知识的人。
     
  • 相关阅读:
    Java-集合类汇总
    Java-ArrayList
    Java-ArrayList和Vector的区别
    Java-List
    Java-Stack
    Java-Vector
    Java-HashMap
    Java-EnumSet
    18校招借鉴
    spring的设计模式
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14508872.html
Copyright © 2011-2022 走看看