• 《C++新经典》第16章 智能指针



    智能指针防止内存泄漏,自动释放。

    16.1 直接内存管理(new/delete)、创建新工程与观察内存泄漏

    16.1.1 直接内存管理(new/delete)

    new变量,动态分配,堆分配,需delete释放。

    int *pi = new int; //未定义
    int *pi2 = new int();//初始化0
    int *pi3 = new int(100);
    
    string *ps = new string;//断点调试发现""
    string *ps2 = new string();//""
    
    vector<int> *pv = new vector<int>{1, 2, 3};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    class A {
    public:
    	A() {
    		cout <<"A()" <<endl;
    	}
    	int m_i;
    };
    
    //自定义类,两者等价
    A *p1 = new A;
    A *p2 = new A();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    string* ps2 = new string(5, 'a');
    string** ps3 = new (string *)(ps2);
    //auto ps3 = new auto(ps2);//与上面等价
    
    
    delete ps2;
    delete ps3;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    const int *pi = new const int(200);//new后面const可省略
    //*pi = 300;//错误
    delete pi;//可以delete const对象
    
    • 1
    • 2
    • 3

    16.1.2 创建新工程与观察内存泄漏

    通过创建MFC应用项目来观察内存泄漏。

    16.2 new/delete探秘、智能指针总述与shared_ptr基础

    16.2.1 new/delete探秘

    1. new/delete是什么
      new和delete都是关键字(运算符/操作符),不是函数。
      new比较malloc,除了分配内存,还有初始化工作;
      delete比较free,除了释放内存,还有清理工作。
    class A {
    public:
    	A(){cout<<"A()"<<endl;}
    	~A(){cout<<"~A()"<<endl;}
    };
    
    A* pa = new A(); //调用构造函数
    delete pa;//调用析构函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. operator new()和operator delete()
      重载运算符,实际表现就是函数。
    void *p=operator new(100);//分配100各字节,malloc?
    
    • 1

    new运算符做了两件事:分配内存(通过调用operator new(…)),调用构造函数初始化该内存。

    delete运算符做了两件事:调用析构函数,释放内存(通过调用operator delete(…))。

    1. new如何记录分配的内存大小供delete使用
    int *p=new int;//分配4个字节
    delete p;
    //new内部有记录机制,记录分配字节数,用于delete时回收
    
    • 1
    • 2
    • 3
    1. 申请和释放一个数组
      new[]与delete[]
    A *pA=new A[2](); //会多分配4个字节,专门保存数组大小
    delete[] pA;//delete[]时,取出数组大小,调用多次析构函数
    
    • 1
    • 2
    1. 为什么new/delete、new []/delete []要配对使用
      内置类型或者无自定义析构函数的类类型,new[]时不会多分配4个字节,delete与delete[]等价?(需测试)

    delete与delete[],调用析构函数次数不同,释放内存大小不同(多分配4个字节)。

    16.2.2 智能指针总述

    new对象返回的对象指针称为裸指针(无包装)。
    智能指针对裸指针进行了包装,能够自动释放所指向的对象,管理动态分配的new对象的生命周期,有效防止内存泄漏。

    三种智能指针都是类模板(使用<>):

    • shared_ptr
      共享式指针,多个指针指向同一个对象,最后一个指针销毁时,对象被释放。

    • weak_ptr
      辅助shared_ptr工作。

    • unique_ptr(完全取代auto_ptr)
      独占式指针,同一时间只有一个指针指向该对象,对象所有权可以移交出去。

    16.2.3 shared_ptr基础

    对象被多个shared_ptr共享,使用引用计数工作,最后一个指向该对象的指针被析构或者指向其它对象时,该对象被释放。

    shared_ptr<string> p;
    
    • 1
    1. 常规初始化
    shared_ptr<int> pi(new int(100));
    //错误,智能指针explicit,禁止隐式类型转换
    shared_ptr<int> pi2 = new int(100);
    
    
    shared_ptr<int> makes(int value) {
    	//return new int(value);//错误,int*与shared_ptr不等
    	return shared_ptr<int>(new int(value)); 
    }
    
    int *pi = new int;
    //不推荐
    //shared_ptr p1(pi);
    shared_ptr<int> p1(new int);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. make_shared函数
      make_shared生成的shared_ptr没办法自定义删除器。
    shared_ptr<int> p2 = std::make_shared<int>(100);
    //make_shared后面参数需与string里某个构造函数匹配
    shared_ptr<string> p3 = std::make_shared<string>(5, 'a');
    
    shared_ptr<int> p4 = std::make_shared<int>();//0
    p4 = std::make_shared<int>(400);//p4释放刚才的对象,重新指向新对象
    
    auto p5 = std::make_shared<string>(5, 'a');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    16.3 shared_ptr常用操作、计数与自定义删除器等

    16.3.1 shared_ptr引用计数的增加与减少

    1. 引用计数增加
    auto p6=std::make_shared<int>(100);
    auto p7(p6);//或者auto p7=p6;
    //两个引用计数
    
    void myfunc(shared_ptr<int> ptmp){
    	//实参传递会增加,引用传递不增加
    	return;//退出函数,引用不变
    }
    
    make_shared<int> myfunc2(shared_ptr<int> &ptmp){
    	//引用传递不增加
    	return ptmp;
    }
    myfunc2(p7); //无接收变量,引用不增加
    auto p8=myfunc2(p7); //有接收变量,引用+1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 引用计数减少
    p8=std::make_shared<int>(100);//p8指向新对象计数1,p6、p7计数恢复2
    
    p7=std::make_shared<int>(200);//p7指向新对象计数1,p6计数恢复2
    
    p6=std::make_shared<int>(300);//p6指向新对象计数1,p6指向原对象内存被释放
    
    p8=p7;//p7指向对象计数2,p8指向原对象内存被释放
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    16.3.2 shared_ptr常用操作

    1. use_count
      引用个数
    shared_ptr<int> myp(new int(100));
    int icount=myp.use_count();//1
    
    shared_ptr<int> myp2(myp);
    icount=myp.use_count();//2
    
    shared_ptr<int> myp3;
    myp3=myp2;
    icount=myp.use_count();//3
    icount=myp3.use_count();//3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. unique
      是否只有一个智能指针指向某个对象。
    shared_ptr<int> myp(new int(100));
    if(myp.unique())
    	cout<<"unique\n";
    	
    shared_ptr<int> myp2(myp);
    if(myp.unique())
    	cout<<"unique\n";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. reset
      (1)无参数
      原指向对象引用参数减1(为0则释放空间),同时智能指针置空。
    shared_ptr<int> p(new int(100));
    p.reset();
    
    if(p==nullptr)
    	cout<<"empty"<<end;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)带参数(一般new指针)
    原指向对象引用参数减1(为0则释放空间),同时智能指针指向新分配对象。

    shared_ptr<int> pi(new int(100));
    auto pi2(pi);
    pi.reset(new int(100));
    
    • 1
    • 2
    • 3
    1. *解引用
      获得指向的对象。
    shared_ptr<int> p(new int(100));
    char buf[256];
    sprintf(buf, sizeof(buf), "%d", *p);
    
    • 1
    • 2
    • 3
    1. get
      返回指向对象的指针。
    shared_ptr<int> myp(new int(100));
    int* p=myp.get();
    *p=34;
    
    • 1
    • 2
    • 3
    1. swap
      交换两个指针所指对象。
    shared_ptr<string> p1(new string("str1"));
    shared_ptr<string> p2(new string("str2"));
    std::swap(p1, p2);
    p1.swap(p2);
    
    • 1
    • 2
    • 3
    • 4
    1. =nullptr;
      智能指针置空,且指向对象引用计数减1。
    shared_ptr<string> p1(new string("str1"));
    p1=nullptr;
    
    • 1
    • 2
    1. 智能指针名字用于判断
    shared_ptr<string> p1(new string("str1"));
    if(p1)
    	cout<<*p1<<end;
    
    • 1
    • 2
    • 3
    1. 指定删除器和数组问题
      (1)指定删除器
      默认使用delete运算符删除指定对象(不支持数组对象,析构函数类也不支持)。
      可指定删除器,参数中添加删除器函数名(单形参)。
    void myDeleter(int *p){
    	delete p;
    }
    
    shared_ptr<int> p(new int(100), myDeleter);
    p.reset();
    
    
    shared_ptr<int> p(new int(100), [](int *p){
    	delete p;
    });
    p.reset();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    shared_ptr<int> p(new int[8], [](int *p){
    	delete[] p;
    });
    p.reset();
    //或者
    shared_ptr<int[]> p(new int[8]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    class A {
    public:
    	A(){cout<<"A()\n";}
    	~A(){cout<<"~A()\n";}
    };
    
    shared_ptr<A> pA(new A[8], [](A *p){
    	delete[] p;
    });
    p.reset();
    
    //或者
    shared_ptr<A> pA(new A[8], std::default_delete<A[]>());
    shared_ptr<A[]> pA(new A[8]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    自己写模板封装shared_ptr数组

    template<typename T>
    shared_ptr<T> make_shared_array(size_t size) {
    	return shared_ptr<T> (new T[size], std::default_delete<T[]>());
    }
    
    
    shared_ptr<int> p = make_shared_array<int>(5);
    shared_ptr<A> pA = make_shared_array<A>(5);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (2)额外说明
    shared_ptr指定删除器不同,但指向对象相同,这两个shared_ptr属于同一个类型。

    auto lambda1 = [](int *p) {delete p;};
    auto lambda2 = [](int *p) {delete p;};
    
    shared_ptr<int> p1(new int(100), lambda1);
    shared_ptr<int> p2(new int(200), lambda2);
    
    p2 = p1;
    //先调用lambda2释放p2指向对象,然后p2指向p1所指对象。
    //最后lambda1释放p1、p2共同指向对象。
    
    vector<shared_ptr<int>> pvec{p1, p2};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    16.4 weak_ptr简介、常用操作与尺寸问题

    16.4.1 weak_ptr简介

    weak_ptr绑定到shared_ptr上并不改变shared_ptr的引用计数。
    weak_ptr,能力弱(弱共享/弱引用,共享其它shared_ptr指向的对象),控制不了所指向对象的生成期。

    弱引用,用来监视强引用(shared_ptr)的生命周期(能监视到指向对象是否存在),是shared_ptr的助手(旁观者)。

    auto pi = make_shared<int>(100);
    weak_ptr<int> piw(pi);
    weak_ptr<int> piw2;
    piw2=piw;
    
    //不能使用weak_ptr直接访问对象。
    //lock()返回shared_ptr,可判断指向对象是否存在(nullptr)
    auto pi2=piw.lock();
    if(pi2)
    	cout<<"exists";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    16.4.2 weak_ptr常用操作

    1. use_count
      强引用计数。
    auto pi = make_shared<int>(100);
    auto pi2(pi);
    weak_ptr<int> piw(pi);
    int isc = piw.use_count();	//2
    
    • 1
    • 2
    • 3
    • 4
    1. expired
      观测对象(资源)是否已经被释放。
    pi.reset();
    pi2.reset();
    if(piw.expired())
    	cout<<"empty";
    
    • 1
    • 2
    • 3
    • 4
    1. reset
      弱引用指针置空。
    auto pi = make_shared<int>(100);
    weak_ptr<int> piw(pi);
    piw.reset();
    
    • 1
    • 2
    • 3
    1. lock
      获取所监视的shared_ptr。
    auto pi = make_shared<int>(100);
    weak_ptr<int> piw;
    pw=pi;
    if(!pw.expired()) {
    	auto p2 = pw.lock();
    	if(p2 != nullptr)
    		cout<<"exist";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    weak_ptr<int> piw;
    {
    	auto pi = make_shared<int>(100);
    	pw=pi;
    }
    
    if(pw.expired()) {
    	cout<<"empty";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    16.4.3 尺寸问题

    weak_ptr|shared_ptr的尺寸(sizeof)是裸指针的2倍。

    shared_ptr<int> p(new int(100));
    weak_ptr<int> pw(p);
    sizeof(int *);	//4,x86
    sizeof(p);	//8,x86
    sizeof(pw);	//8,x86
    
    • 1
    • 2
    • 3
    • 4
    • 5

    包含两个裸指针:
    (1)指向智能指针所指向的对象。
    (2)指向数据结构(控制块,shared_ptr创建),里面包含:

    • 所指对象的引用计数;
    • 所指对象的弱引用计数;
    • 其它数据,自定义的删除器的指针(若指定)等。

    16.5 shared_ptr使用场景、陷阱、性能分析与使用建议

    16.5.1 shared_ptr使用场景

    shared_ptr<int> myfunc(int value) {
    	return make_shared<int>(value);
    }
    
    auto p = myfunc(12);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16.5.2 shared_ptr使用陷阱分析

    1. 慎用裸指针
    void proc(shared_ptr<int> ptr){
    	return;
    }
    
    int *p=new int(100);
    //proc(p);//int*不能转换为shared_ptr
    proc(shared_ptr<int>(p));//离开proc后,p指向内存已被释放。
    *p=45;//error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    //修改为

    shared_ptr<int> p(new int(100));
    proc(p);
    *p=45;
    
    • 1
    • 2
    • 3
    int *p=new int(100);
    
    //p指向内存释放两次,error
    shared_ptr<int> p1(p);
    shared_ptr<int> p2(p);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    //改为

    shared_ptr<int> p1(new int(1));
    shared_ptr<int> p2(new int(1));
    
    • 1
    • 2
    1. 慎用get返回指针
    shared_ptr<int> myp(new int(1));
    int *p=myp.get();
    //delete p;//error
    {
    	//shared_ptr myp2(p); //error
    	shared_ptr<int> myp2(myp); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. enable_shared_from_this返回this
    class CT {
    public:
    	shared_ptr<CT> getself() {
    		return shared_ptr<CT>(this);
    	}
    };
    
    shared_ptr<CT> p1(new CT);
    shared_ptr<CT> p2 = p1; //ok,两个强引用
    
    
    shared_ptr<CT> p3 = p1->getself();//error,同一个指针this构造了两个无关联的智能指针,会释放两次
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    //enable_shared_from_this,类模板
    class CT:public std::enable_shared_from_this<CT> {
    public:
    	shared_ptr<CT> getself() {
    		//return shared_ptr(this);
    		return shared_from_this();
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    shared_from_this工作原理:
    enable_shared_from_this是类模板,类型模板参数是继承的子类的类名,该类模板中有一个弱指针weak_ptr(观测this),调用shared_from_this方法实际是调用weak_ptr的lock方法,返回shared_ptr。

    1. 避免循环引用
    class CA;
    class CB;
    
    class CA {
    public:
    	shared_ptr<CB> m_pbs;
    	~CA() {
    		cout<<"~CA()"<<endl;
    	}
    };
    class CB {
    public:
    	shared_ptr<CA> m_pas;
    	~CB() {
    		cout<<"~CB()"<<endl;
    	}
    };
    
    shared_ptr<CA> pca(new CA);
    shared_ptr<CB> pcb(new CB);
    pca->m_pbs = pcb;
    pcb->m_pas = pca;
    //CA,CB对象有两个引用计数,离开作用域后变成1个,不会被释放,内存泄漏。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    //修改CA或CB中成员变量为weak_ptr

    class CA;
    class CB;
    
    class CA {
    public:
    	shared_ptr<CB> m_pbs;
    	~CA() {
    		cout<<"~CA()"<<endl;
    	}
    };
    class CB {
    public:
    	weak_ptr<CA> m_pas;
    	~CB() {
    		cout<<"~CB()"<<endl;
    	}
    };
    
    shared_ptr<CA> pca(new CA);
    shared_ptr<CB> pcb(new CB);
    pca->m_pbs = pcb;//CB两个强引用
    pcb->m_pas = pca;//CA一个强引用
    //先执行CA类析构函数(释放CA中一个CB强引用),后执行CB类析构函数(CA类不释放,CB类强引用不可能为0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    16.5.3 性能说明

    1.尺寸问题
    shared_ptr创建控制块的时机:
    (1)make_shared分配并初始化一个对象时。

    shared_ptr<int> p=std::make_shared<int>(100);
    
    • 1

    (2) 指针创建shared_ptr对象时。

    int *pi=new int;
    shared_ptr<int> p(pi);
    //或者
    shared_ptr<int> p(new int);
    
    • 1
    • 2
    • 3
    • 4

    2.移动语义

    shared_ptr<int> p1(new int(1));
    shared_ptr<int> p2(std::move(p1));//p1空,引用计数1
    shared_ptr<int> p3;
    p3 = std::move(p2);//p2空,引用计数1
    
    • 1
    • 2
    • 3
    • 4

    复制使shared_ptr的引用计数递增,移动不会使shared_ptr的引用计数递增。

    16.5.4 补充说明的使用建议

    shared_ptr可以提供删除器和分配器(解决内存分布问题,保存在控制块中)。

    shared_ptr<int> p(new int(), myDeleter(), myMallocator<int>());
    
    • 1

    优先使用make_shared构造智能指针,编译器内部会有针对内存分配的特殊处理,使make_shared效率更高,如消除重复代码、改进安全性等。

    shared_ptr<string> p1(new string("hello"));
    //至少分配两次内存
    //构造string实例分配内存
    //shared_ptr构造函数中shared_ptr控制块分配内存
    
    • 1
    • 2
    • 3
    • 4

    16.6 unique_ptr简介与常用操作

    16.6.1 unique_ptr简介

    独占式智能指针,专属所有权,同一时刻,智能指针。

    1. 常规初始化(unique_ptr和new配合)
    unique_ptr<int> pi(new int(15));
    
    auto p2(new int(15));//此时p2为int*
    
    • 1
    • 2
    • 3
    1. make_unique(C++14)
      优先使用,更高性能。想自定义删除时不能使用。
    unique_ptr<int> p1 = std::make_unique<int>(15);
    auto p2 = std::make_unique<int>(200);
    
    • 1
    • 2

    16.6.2 unique_ptr常用操作

    1. 不支持操作
      不允许复制、赋值等动作,只能移动不能复制的类型。
    auto ps1 = std::make_unique<string>("hello");
    unique_ptr<string> ps2(ps1);	//error
    unique_ptr<string> ps3 = ps1;	//error
    unique_ptr<string> ps4;
    ps4 = ps1;	//error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 移动语义
    auto ps1 = std::make_unique<string>("hello");
    unique_ptr<string> ps4;
    ps4 = std::move(ps1);	//ok
    
    • 1
    • 2
    • 3
    1. release
    unique_ptr<string> ps1(new string("hello"));
    unique_ptr<string> ps2(ps1.release());
    if(ps1 == nullptr)
    	cout<<"ps1 release()"<<endl;
    
    //ps2.release();//会导致内存泄漏
    string *tmp = ps2.release();
    delete tmp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. reset
    unique_ptr<string> ps1(new string("hello"));
    ps1.reset();//释放ps1指向对象,并将ps1置空
    if(ps1 == nullptr)
    	cout<<"ps1 reset()"<<endl;
    
    • 1
    • 2
    • 3
    • 4
    unique_ptr<string> ps1(new string("hello"));
    unique_ptr<string> ps2(new string("hello2"));
    ps2.reset(ps1.release());//释放ps2指向内存,并重新指向ps1指向的内存,同时ps1被置空
    ps2.reset(new string("hello2"));//释放ps2指向内存,并重新指向新分配的内存
    
    • 1
    • 2
    • 3
    • 4
    1. =nullptr;
    unique_ptr<string> ps1(new string("hello"));
    ps1 = nullptr;//释放ps1指向内存,同时ps1被置空
    
    • 1
    • 2
    1. 指向数组
    std::unique_ptr<int[]> ptrarray(new int[10]);
    ptrarray[0] = 12;
    ptrarray[1] = 24;
    ptrarray[9] = 124;
    
    • 1
    • 2
    • 3
    • 4
    class A{
    public:
    	A(){}
    	~A(){}
    };
    
    //error
    //std::unique_ptr ptrarray(new A[10]);
    
    //自己的删除器
    auto mydel = [](A* p) {
    	delete[] p;
    };
    std::unique_ptr<A, decltype(mydel)> ptrarray2(new A[10], mydel);
    std::unique_ptr<A[]> ptrarray(new A[10]);
    
    1. get
      返回裸指针。
    unique_ptr<string> ps1(new string("hello"));
    string *ps = ps1.get();
    const char *p1 = ps->c_str();
    *ps="new string";
    const char *p2 = ps->c_str();
    //p1和p2指向不同的内存地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. *解引用
    unique_ptr<string> ps1(new string("hello"));
    *ps1="new string";
    
    • 1
    • 2
    1. swap
    unique_ptr<string> ps1(new string("hello"));
    unique_ptr<string> ps2(new string("hello2"));
    std::swap(ps1, ps2);
    ps1.swap(ps2);
    
    • 1
    • 2
    • 3
    • 4
    1. 名字判断
    unique_ptr<string> ps1(new string("hello"));
    if(ps1)
    	cout<<"point"<<endl;
    
    • 1
    • 2
    • 3
    1. 转换为shared_ptr类型
    auto myfunc(){
    	return unique_ptr<string>(new string("hello")); //右值
    }
    shared_ptr<string> ps1 = myfunc();
    
    • 1
    • 2
    • 3
    • 4
    unique_ptr<string> ps(new string("hello")); 
    shared_ptr<string> ps2 = std::move(ps);
    
    • 1
    • 2

    16.7 返回unique_ptr、删除器与尺寸问题

    16.7.1 返回unique_ptr

    unique_ptr不能被复制,将要被销毁时,可以被复制。

    
    unique_ptr<string> myfunc(){
    	unique_ptr<string> pr(new string("hello"));
    	return pr;
    	//return unique_ptr(new string("hello"));
    }
    
    
    unique_ptr<string> ps; 
    ps = myfunc();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    16.7.2 删除器

    1. 指定删除器
    unique_ptr<指向的对象类型,删除器> 智能指针变量名; 
    //删除器就是可调用对象
    
    • 1
    • 2
    void mydeleter(string *pdel){
    	delete pdel;
    	pdel = nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    typedef void(*fp)(string *);
    unique_ptr<string, fp> ps(new string("hello"), mydeleter);
    
    • 1
    • 2
    using fp = void(*)(string *);
    unique_ptr<string, fp> ps(new string("hello"), mydeleter);
    
    • 1
    • 2
    //decltype返回函数类型,*表示函数指针类型
    //fp是void *(string *)
    typedef decltype(mydeleter)* fp;
    unique_ptr<string, fp> ps(new string("hello"), mydeleter);
    
    • 1
    • 2
    • 3
    • 4
    unique_ptr<string, decltype(mydeleter)*> ps(new string("hello"), mydeleter);
    
    • 1
    auto mydella = [](string *pdel){
    	delete pdel;
    	pdel = nullptr;
    }
    unique_ptr<string, decltype(mydella)> ps(new string("hello"), mydella);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 额外说明

    share_ptr指定删除器不同,但指向对象相同,属于同一个类型,可放在同一个容器内。
    unique_ptr指定删除器不同,类型不同,不能放在同一个容器内。

    16.7.3 尺寸问题

    unique_ptr一般和裸指针一样,lambda表达式删除器,尺寸不会变;函数删除器,尺寸会变化。

    string *p;
    sizeof(p);//4
    unique_ptr<string> ps(new string("hello"));
    sizeof(ps)//4
    
    • 1
    • 2
    • 3
    • 4

    16.8 智能指针总结

    1. 背后设计思想
      帮助释放内存,防止内存泄漏。
    void myfunc(){
    	//string *ps=new string("hello");
    	unique_str<string> ps(string("hello"));
    	//...
    	if(true){
    		//delete ps;
    		return;
    	}
    	
    	//delete ps;
    	return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 使用unique_ptr替代auto_ptr
    shared<string> ps(string("hello"));
    shared<string> ps2=ps;
    
    • 1
    • 2
    unique_ptr<string> ps(new string("hello"));
    //unique_ptr ps2=ps;//error
    //unique_ptr ps2(ps);//error
    unique_ptr<string> ps2=std::move(ps);
    
    • 1
    • 2
    • 3
    • 4
    1. 选择
      需要多个指向同一对象的指针,选择shared_ptr;
      不需要多个指向同一对象的指针,选择unique_ptr。
  • 相关阅读:
    FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
    Windows server 2012 R2系统服务器远程桌面服务激活服务器RD授权分享
    2018年亚太杯APMCM数学建模大赛A题老年人平衡能力的实时训练模型求解全过程文档及程序
    Java 21 新特性:switch的模式匹配
    设备自动化系统EAP在晶圆厂的关键作用
    白嫖阿里云服务器教程来了,薅秃阿里云!
    ubuntu16.04部署nginx(无网络)
    PTE考试解析
    文心一言 VS 讯飞星火 VS chatgpt (183)-- 算法导论13.4 7题
    高级前端开发需要知道的 25 个 JavaScript 单行代码
  • 原文地址:https://blog.csdn.net/oqqyx1234567/article/details/126040328