• 智能指针 之 unique_ptr shared_ptr weak_ptr




    智能指针注意事项

    • 智能指针就是类,类中有一个成员管理着原始指针(他自己的地址和他管理的指针地址是两个东西)
    • 智能指针的目的是解决资源释放问题
    • 智能指针不支持指针运算:+,-,++,–
      但是常规指针支持

    独占指针 unique_str

    独占指针独享它指向的对象

    初始化

    方法①
    	stu* s1 = new stu("Alice");//类new必须是指针
    	unique_ptr  u1(s1);
    方法②【常用】
    	unique_ptru2(new stu("Bob"));
    方法③【C++14标准】
    	unique_ptru3 = make_unique("Cindy");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用(相关函数)

      u1->name;
      (*u1).name;//解引用 
    
    • 1
    • 2

    赋值nullptr释放对象

    赋值NULL后对象被释放,抛出异常

    在这里插入图片描述

    release 释放控制权

    释放对原始指针的控制权,将unique_ptr置为空,返回裸指针
    如下图(释放后仍调用会异常)

    在这里插入图片描述

    move转变原指针控制权

    在这里插入图片描述

    reset()释放对象

    	u1.reset();//释放u1指向的资源对象
    	u1.reset(nullptr);//释放u1指向的资源对象
    	u1.reset(new stu("Bob"));//释放u1指向的资源对象,并指向新的
    
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    unique_ptr赋值原则

    将一个unique_ptr指针赋给另一个时遵循的原则:
    右值如果会继续存在则不能赋值(如下不被允许)

    unique_ptr  u1(new stu("alice"));
    unique_ptr  u2;
    u2 = u1 ;//是错误的,因为u1会继续存在
    
    • 1
    • 2
    • 3

    右值时临时变量则可以赋值(如下被允许)

    unique_ptr  u2;
    u2 = fun();
    unique_ptr  fun(){
     unique_ptr s1(new stu("alice"));
     return s1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    多态 demo

    #include 
    #include 
    using namespace std;
    class base {
    public:
    	virtual void show1() = 0;//纯虚函数
    	virtual void show2() {}//虚函数
    
    };
    class son1 :public base{
    public:
    	void show1();
    	void show2();
    };
    void son1::show1() {
    	cout << "我是孩子1号重写了base类show1函数" << endl;
    }
    void son1::show2() {
    	cout << "我是孩子1号我重写了base类show2函数" << endl;
    }
    class son2 :public base {
    public:
    	void show1();
    	void show2();
    };
    void son2::show1() {
    	cout << "我是孩子2号重写了base类show1函数" << endl;
    }
    void son2::show2() {
    	cout << "我是孩子2号我重写了base类show2函数" << endl;
    }
    
    
    int main() {
    	int id;
    	while (1) {
    		cin >> id;
    		if (id == 1) {
    			unique_ptr <son1> u1(new son1);
    			u1->show1();
    			u1->show2();
    		}
    		else {
    			unique_ptr <son2> u1(new son2);
    			u1->show1();
    			u1->show2();
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    智能指针不是绝对安全的

    如果在程序中调用exit()退出,全局unique_ptr可以自动释放,局部的无法释放

    智能指针数组

    常规类数组指针demo

    用完必须手动释放
    delete []arr;

    #include 
    #include 
    using namespace std;
    class base {
    public:
    	virtual void show1() = 0;
    	virtual void show2() {}
    public:
    	string name;
    };
    class son1 :public base{
    public:
    	void show1();
    	void show2();
    };
    void son1::show1() {
    	cout << "我是孩子1号重写了base类show1函数" << endl;
    	cout <<"我叫:" << name << endl;
    }
    void son1::show2() {
    	cout << "我是孩子1号我重写了base类show2函数" << endl;
    }
    class son2 :public base {
    public:
    	void show1();
    	void show2();
    };
    void son2::show1() {
    	cout << "我是孩子2号重写了base类show1函数" << endl;
    	cout << "我叫:" << name << endl;
    }
    void son2::show2() {
    	cout << "我是孩子2号我重写了base类show2函数" << endl;
    }
    
    int main() {
    	son1* arr = new son1[2];//普通指针数组
    	arr[0].name = "Alice";
    	arr[1].name = "Bob";
    	arr[0].show1();
    	arr[0].show2();
    	arr[1].show1();
    	arr[1].show2();
    	delete[]arr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    智能数组指针demo
    #include 
    #include 
    using namespace std;
    class base {
    public:
    	virtual void show1() = 0;
    	virtual void show2() {}
    public:
    	string name;
    };
    class son1 :public base{
    public:
    	void show1();
    	void show2();
    };
    void son1::show1() {
    	cout << "我是孩子1号重写了base类show1函数" << endl;
    	cout <<"我叫:" << name << endl;
    }
    void son1::show2() {
    	cout << "我是孩子1号我重写了base类show2函数" << endl;
    }
    class son2 :public base {
    public:
    	void show1();
    	void show2();
    };
    void son2::show1() {
    	cout << "我是孩子2号重写了base类show1函数" << endl;
    	cout << "我叫:" << name << endl;
    }
    void son2::show2() {
    	cout << "我是孩子2号我重写了base类show2函数" << endl;
    }
    
    int main() {
    	unique_ptr <son2[] > arr( new son2[2]);//普通指针数组
    	arr[0].name = "Alice";
    	arr[1].name = "Bob";
    	arr[0].show1();
    	arr[0].show2();
    	arr[1].show1();
    	arr[1].show2();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    函数后加delete表示禁用该函数(c++11)

    unique_ptr禁用了拷贝构造函数和赋值函数

    unique_ptr(const unique_ptr &)=delete;
    unique_ptr& operator=(const unique_ptr&)=delete;
    
    • 1
    • 2

    如下代码仅用了拷贝构造函数

     stu(string name) = delete;
    
    • 1

    在这里插入图片描述

    unique_ptr注意事项

    智能指针是类,可以传地址,如

    fun(&pu);
    void fun(unique_ptr*p){
    	cout<<(*p)->name;
    }
    
    • 1
    • 2
    • 3
    • 4

    但是首推引用,不能值传递

    fun(pu);
    void fun(unique_ptr&p){
    	cout<< p->name;
    }
    
    • 1
    • 2
    • 3
    • 4

    共享指针 shared_ptr

    • 多个共享指针可以指向相同的对象(同一个)
      【资源没有被复制,只是被共享】
    • unique_ptr能解决问题不要用shared_ptr,前者更高效,占用资源更少

    初始化

    方法①
    	stu* s1 = new stu("Alice");//类new必须是指针
    	shared_ptr  u1(s1);
    方法②【常用】
    	shared_ptru2(new stu("Bob"));
    方法③【C++11标准】【推荐】
    	shared_ptru3 = make_unique("Cindy");
    方法④【注意格式】【无拷贝构造】
    	shared_ptr  u1(new stu("Alice"));
    	shared_ptr  u2(u1);//可以用括号
    	shared_ptr  u3 = u1;//可以用等号
    	cout << u3.use_count() << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用(相关函数)

      u1->name();
      (*u1).name;//解引用 
    
    • 1
    • 2

    shared_ptr支持赋值[unique_ptr看情况]

    	shared_ptr  u2(u1);//可以用括号
    	shared_ptr  u3 = u1;//可以用等号
    
    • 1
    • 2
    • 赋值后左值计数器-1,右值计数器+1
    • 指向资源的指针多一个就+1,少一个就-1
    • 计数器为0会释放资源
    	shared_ptr  a1(new stu("Alice"));
    	shared_ptr  a2(a1);//可以用括号
    	shared_ptr  a3 = a1;//可以用等号
    	shared_ptr  b1(new stu("Alice"));
    	shared_ptr  b2(b1);//可以用括号
    	cout <<"a.count=" << a1.use_count() << endl;
    	cout <<"b.count=" << b1.use_count() << endl;
    	//a1赋给b1,相当于覆盖了一个b1,b1-1
    	b1 = a1;
    	cout << "a.count=" << a1.use_count() << endl;
    	cout << "b.count=" << b2.use_count() << endl;
    	b2 = b1;
    	cout << "a.count=" << a1.use_count() << endl;
    	cout << "b.count=" << b2.use_count() << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    计数函数 use_count()

    在这里插入图片描述

    unique() 1为True其他False

    不为1为False(为2、3、4都不行)
    在这里插入图片描述
    必须是1
    在这里插入图片描述

    其他函数与unique_ptr类似不做演示

    智能指针删除器

    (缺省删除器)默认情况下,智能指针过期后用delete释放管理的资源,但是程序猿可以自定义删除器,改变释放资源的行为
    【形参为原始指针】

    unique_ptr删除器[decltype]

    缺省|全局函数|lambda|仿函数

    	//缺省
    	unique_ptr  a11(new stu("Alice"));
    	//普通函数
    	unique_ptr  a1(new stu("Alice"), delet);
    	//lambda
    	unique_ptr < stu, decltype(delet_lambda) > a2(new stu("Bob"), delet_lambda);//可以用括号
    	//仿函数
    	unique_ptr  a3(new stu("Carry"),dele());
    	a1.reset();
    	a2.reset();
    	a3.reset();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    shared_ptr删除器件

    缺省|全局函数|lambda|仿函数

    #include 
    #include 
    using namespace std;
    class stu {
    public:
    	stu(string name) : name(name) {}
    	string name;
    };
    class dele {
    public:
    	void operator()(stu* a) {
    		cout << "仿函数,自定义删除器删除" << endl;
    		delete a;
    	}
    
    };
    void delet(stu* a) {
    	cout << "全局函数,自定义删除器删除" << endl;
    	delete a;
    }
    auto delet_lambda = [](stu *a) {
    	cout << "lambda函数,自定义删除器删除" << endl;
    	delete a;
    };
    int main() {
    	shared_ptr  a11(new stu("Alice"));//缺省
    	shared_ptr  a1(new stu("Alice"),delet);
    	shared_ptr  a2(new stu("Bob"),delet_lambda);//可以用括号
    	shared_ptr  a3(new stu("Carry"),dele());
    	a1.reset();
    	a2.reset();
    	a3.reset();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    weak_ptr

    为了解决循环引用导致技术永远无法归0,资源部会被释放的问题
    weak_ptr是为了配合shared_ptr而引入的,它可以指向一个由shared_ptr管理的资源但不影响生命周期,即绑定之后weak_ptr不影响shared_ptr的引用周期但是他知道对象是否还活着
    -【weak_ptr更像shared_ptr的助手,解决它无法处理的循环问题】

    shared_ptr出现的问题

    【引用计数器失灵,双方都在循环等待对方释放】

    #include 
    #include 
    
    using namespace std;
    class tec;//要先声明tec,不然stu在声明tec时会未定义
    class stu {
    public:
    	string name;
    	stu(string name) : name(name) {
    		cout << "我是stu的有参构造函数,我是" << name << endl;
    	}
    	~stu() {
    		cout << "我是stu的析构函数,我是" << name << endl;
    	}
    	shared_ptr <tec> aa;
    };
    class tec{
    public:
    	string name;
    	tec(string name) : name(name) {
    		cout << "我是stu的有参构造函数,我是" << name << endl;
    	}
    	~tec() {
    		cout << "我是stu的析构函数,我是" << name << endl;
    	}
    	shared_ptr <stu> aa;
    };
    int main() {
    	
    	shared_ptr <stu> student= make_shared <stu> ("Alice");
    	shared_ptr <tec> teacher = make_shared <tec>("Bob");
    	teacher->aa = student;
    	student->aa = teacher;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    只调用构造不调用析构,很不正常
    【引用计数器失灵,双方都在等待对方释放】
    在这里插入图片描述
    使用weak_ptr之后成功解决
    在这里插入图片描述

    weak_ptr 成员函数

    没有重载->和*,所以不能直接访问资源

    operator=()赋值

    已经展示过

    exptred()判断是否过期

    #include 
    #include 
    
    
    using namespace std;
    class tec;//要先声明tec,不然stu在声明tec时会未定义
    class stu {
    public:
    	string name;
    	stu(string name) : name(name) {
    		cout << "我是stu的有参构造函数,我是" << name << endl;
    	}
    	~stu() {
    		cout << "我是stu的析构函数,我是" << name << endl;
    	}
    	weak_ptr  aa;
    };
    class tec{
    public:
    	string name;
    	tec(string name) : name(name) {
    		cout << "我是stu的有参构造函数,我是" << name << endl;
    	}
    	~tec() {
    		cout << "我是stu的析构函数,我是" << name << endl;
    	}
    	weak_ptr  aa;
    };
    int main() {
    	
    	shared_ptr  student = make_shared ("Alice"); 
    	{
    		shared_ptr  teacher = make_shared ("Bob");
    		//Bob仅在代码块内声明,代码块外无Bob
    		teacher->aa = student;
    		student->aa = teacher;
    		//weak_ptr提升为shared_ptr
    		shared_ptr  flag = student->aa.lock();
    		if (student->aa.expired())
    			cout << "语句块内部student->aa过期"<aa.lock()->name="
    			<< student->aa.lock()->name << endl;
    	}
    	shared_ptr  flag = student->aa.lock();
    	//代码块外部Bob失效
    	if (student->aa.expired())
    		cout << "语句块内部student->aa过期" << endl;
    	else
    		cout << "语句块内部student->aa.lock()->name="
    		<< student->aa.lock()->name << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这里插入图片描述

    lock()返回shared_ptr

    lock()函数可以提升为shared_ptr,如果对象活着,返回有效的shared_ptr,如果对象死了,提升失败,返回一个空的shared_ptr

    //weak_ptr提升为shared_ptr[线程安全]
    shared_ptr  flag = student->aa.lock();
    
    • 1
    • 2

    reset()置为空|swap()交换|略

    总结

    • 智能指针不支持指针运算:+,-,++,–

    stu类demo

    class stu {
    public:
    	stu(string name) : name(name) {
    		cout << "我是stu的有参构造函数,我是" <
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    weak_ptr线程安全用法

    		//weak_ptr提升为shared_ptr
    		shared_ptr  flag = student->aa.lock();
    
    • 1
    • 2

    代码块

    • 如果在代码块”{}”中定义了变量(定义同一个变量),则该变量的生存周期和作用域将被限制在该代码块内。
      如下图
      在这里插入图片描述
    • 若只对变量赋值会改变全局值
      下图只有赋值没有重新定义
      在这里插入图片描述

    其他内容后续补充

  • 相关阅读:
    Go语言入门篇
    腾讯即将开源微信、QQ都在用的动画神器;Linux Mint与Mozilla达成合作;Apache Flink ML 2.0.0发布 | 开源日报
    java计算机毕业设计中美医院病历管理系统源代码+系统+数据库+lw文档
    Docker 安装oracle12c容器并创建新用户
    一文看懂光模块的工作原理
    同步篇——内核对象
    UE AIPerception感知非Pawn对象
    计算机毕业设计(附源码)python疫情隔离便民系统
    三、nacos注册中心实现原理分析
    ChatGPT驱动下,网站AI客服该如何进步和创新
  • 原文地址:https://blog.csdn.net/weixin_45646601/article/details/127791297