目录
C++指针包含两种
智能指针和原始指针的关系
并不是所有的指针可以封装为智能指针,很多时候原始指针更方便
各种指针中,最常用的是原始指针,其次是unique_ptr和shared_ptr
weak_ptr是share_ptr的一种补充,应用场景少
接下来思考一个问题,为什么有了智能指针,还需要rust呢?
特点:
三种创建方式:
unique_ptr可以通过get()获取地址,另外可以通过->调用成员函数,通过*进行解引用。
- //cat.h
- #ifndef CAT_H
- #define CAT_H
- #include
- #include
- #include "cat.h"
- class Cat
- {
- public:
- Cat(std::string name);
- Cat() = default;
- ~Cat();
- void cat_info() const
- {
- std::cout << "cat info name: " << name << std::endl;
- }
- std::string get_name() const
- {
- return name;
- }
- void set_cat_name(const std::string& name)
- {
- this->name = name;
- }
- private:
- std::string name{ "Mini" };
- };
- #endif
- //cat.cpp
- #include "cat.h"
-
- Cat::Cat(std::string name) : name(name)
- {
- std::cout << "Constructor of Cat :" << name << std::endl;
- }
- Cat::~Cat()
- {
- std::cout << "Destructor of Cat :" << name << std::endl;
- }
- //main.cpp
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- int main(int argc, char *argv[])
- {
- Cat c1("OK");
- c1.cat_info();
- {
- Cat c1("OK");
- c1.cat_info();
- }
- cout << "-------------yz----------" << endl;
- return 0;
- }

- //没有delete由new创建的指针
- #include
- #include
- #inlclude"cat.h"
- using namespace std;
-
- int main()
- {
- Cat *cp1 = new Cat("");
- cp1->cat_info();
- {
- Cat *cp1 = new Cat("yy");
- cp1->cat_info();
- }
- cout<< "-------------yz----------";
- return 0;
- }
以上代码是有问题的,我们没有去释放申请的内存,是不会调用析构函数,内存得不到释放。另外当我们delete两次指针的时候也会出现错误。
因此引入unique_ptr智能指针解决上述问题
代码实现如下
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- int main(int argc, char *argv[])
- {
- //创建unique_ptr方式1
- Cat *cp1 = new Cat("yz");
- std::unique_ptr
u_cp1(cp1) ; - u_cp1->cat_info();
- delete cp1;
- cp1 = nullptr;
-
- cout << "-------------yz----------" << endl;
-
- //创建unique_ptr方式2
- std::unique_ptr
u_cp2(new Cat("gg")) ; - u_cp2->cat_info();
- cout << "-------------yz----------" << endl;
-
- //创建unique_ptr方式3
- std::unique_ptr
u_cp3 = make_unique(); - u_cp3->cat_info();
- return 0;
-
- }
但是需要注意的是,方式一好像在最新的g++编译器上不需要delete和置空操作。如下为我的上述代码的输出。
- Constructor of Cat :yz
- cat info name: yz
- Destructor of Cat :yz
- -------------yz----------
- Constructor of Cat :gg
- cat info name: gg
- -------------yz----------
- cat info name: Mini
- Destructor of Cat :Mini
- Destructor of Cat :gg
- Destructor of Cat :free(): double free detected in tcache 2
- Aborted (core dumped)
如果我将delete操作和置空操作删除,例如
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- int main(int argc, char *argv[])
- {
- //创建unique_ptr方式1
- Cat *cp1 = new Cat("yz");
- std::unique_ptr
u_cp1(cp1) ; - u_cp1->cat_info();
-
- cout << "-------------yz----------" << endl;
-
- //创建unique_ptr方式2
- std::unique_ptr
u_cp2(new Cat("gg")) ; - u_cp2->cat_info();
- cout << "-------------yz----------" << endl;
-
- //创建unique_ptr方式3
- std::unique_ptr
u_cp3 = make_unique(); - u_cp3->cat_info();
- return 0;
-
- }
输出为
- Constructor of Cat :yz
- cat info name: yz
- -------------yz----------
- Constructor of Cat :gg
- cat info name: gg
- -------------yz----------
- cat info name: Mini
- Destructor of Cat :Mini
- Destructor of Cat :gg
- Destructor of Cat :yz
下面介绍解引用和取地址操作,以方式为例
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- int main(int argc, char *argv[])
- {
- //创建unique_ptr方式3
- std::unique_ptr<int> u_cp3 = make_unique<int>(200);
- cout<<"* u_cp3 = "<<* u_cp3<
- cout<<"get adress"<
get()< - return 0;
-
- }
输出为
- * u_cp3 = 200
- get adress0x55e978458e70
3 unique_ptr与函数调用
- unique_ptr是不可Copy,只可以Move
- 在做函数参数或返回值中一定要注意所有权
注意事项:
Passing by value
- 需要注意std::move来转移内存拥有权
- 如果参数之间传入std:make_unique语句 自动转换为move
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- void Passing_by_value( std::unique_ptr
c) { - c->cat_info();
- }
-
- int main(int argc, char *argv[])
- {
- //创建unique_ptr方式3
- std::unique_ptr
u_cp1 = make_unique("haha"); - Passing_by_value(std::move(u_cp1));//需要注意std::move来转移内存拥有权,否则报错。另外move后也不能再使用u_cp1
- Passing_by_value(std::make_unique
("xixi")); -
- return 0;
-
- }
从下面输出结果看到,在move操作转移所有权后会调用Passing_by_value函数和析构函数,说明智能指针不再可用。
- Constructor of Cat :haha
- cat info name: haha
- Destructor of Cat :haha
- Constructor of Cat :xixi
- cat info name: xixi
- Destructor of Cat :xixi
Passing by reference
- 如果设置参数为const则不能改变指向,比如说reset()
- reset()方法为智能指针清空方法。当传常引用时,不可以用reset()清空智能指针。
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- void Passing_by_ref( const std::unique_ptr
&c) { - c->set_cat_name("ee");
- c->cat_info();
- }
-
- int main(int argc, char *argv[])
- {
- //创建unique_ptr方式3
- std::unique_ptr
u_cp1 = make_unique("haha"); - Passing_by_ref(u_cp1);//需要注意std::move来转移内存拥有权,否则报错。另外move后也不能再使用u_cp1
- u_cp1->cat_info();
-
- return 0;
-
- }
由下列输出结果可得,传引用可以修改变量值。
- Constructor of Cat :haha
- cat info name: ee
- cat info name: ee
- Destructor of Cat :ee
Return by value
- 指向一个local object
- 可以作为链式函数
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- std::unique_ptr
get_unique_ptr()//return by value - {
- std::unique_ptr
p_dog = std::make_unique("dog"); - cout<<"unique_ptr adresss"<
get()< - cout<<"unique_ptr adresss"<<&p_dog<
- return p_dog;
- }
-
- int main(int argc, char *argv[])
- {
-
- get_unique_ptr()->cat_info();//链式调用
-
- return 0;
-
- }
输出为
- Constructor of Cat :dog
- unique_ptr adresss0x55a6558e1e70
- unique_ptr adresss0x7ffeb6c9ae70
- cat info name: dog
- Destructor of Cat :dog
4 计数指针 share_ptr
- 计数指针 share_ptr又称为共享指针
- 与unique_ptr不同的是可以共享数据
- share_ptr创建了一个计数器与类对象所指的内存相关联
- Copy则计数加1,销毁则减1
- api为use_count(),查询引用计数
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
-
- int main(int argc, char *argv[])
- {
-
- std::shared_ptr
p1 = make_shared("aa"); - p1->cat_info();
- cout<<"p1 count: "<
use_count()< - std::shared_ptr
p2 = p1; - cout<<"p1 count: "<
use_count()< - cout<<"p2 count: "<
use_count()< - p1=nullptr;
- cout<<"p1 count: "<
use_count()< - cout<<"p2 count: "<
use_count()< - return 0;
-
- }
输出为
- Constructor of Cat :aa
- cat info name: aa
- p1 count: 1
- p1 count: 2
- p2 count: 2
- p1 count: 0
- p2 count: 1
- Destructor of Cat :aa
值得注意的是,无论引用计数为多少,数据只有一套。无论引用计数为多少,程序运行结束时只会调用一次析构函数。
5 shared_ptr与函数
- shared_ptr passed by value :copy时引用计数加1
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- void pass_by_value(std::shared_ptr
c) { - c->cat_info();
- cout<<"count: "<
use_count()< - }
-
- int main(int argc, char *argv[])
- {
-
- std::shared_ptr
p1 = make_shared("aa"); - p1->cat_info();
- pass_by_value(p1);
- cout<<"p1 count: "<
use_count()< -
- return 0;
-
- }
由下面可得,当进入函数体时引用计数加1,离开函数体减1。
- Constructor of Cat :aa
- cat info name: aa
- cat info name: aa
- count: 2
- p1 count: 1
- Destructor of Cat :aa
- shared_ptr passed by ref:const表示不可以改变指向
类似与unique_ptr
- return by value:链式调用
l类似与unique_ptr
6 shared_ptr与unique_ptr
- 不能将shared_ptr转换为unique_ptr
- unique_ptr可以转换为shared_ptr:通过std::move转换
- 将你的函数返回unique_ptr是一种常见的设计模式,这样可以提高代码的复用性,你可以随时改变为shared_ptr
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
- std::unique_ptr
pass_by_value() { - std::unique_ptr
c = make_unique("cc"); - return c;
- }
-
- int main(int argc, char *argv[])
- {
- std::unique_ptr
p0 = make_unique("bb"); - std::shared_ptr
p1 = std::move(p0);//unique_ptr转换为shared_ptr - p1->cat_info();
- cout<<"p1 count: "<
use_count()< -
-
- std::shared_ptr
p3 = pass_by_value();//直接用shared_ptr接收unique_ptr - cout<<"p3 count"<
use_count()< - return 0;
-
- }
输出为
- Constructor of Cat :bb
- cat info name: bb
- p1 count: 1
- Constructor of Cat :cc
- p3 count1
- Destructor of Cat :cc
- Destructor of Cat :bb
7 weak_ptr
- weak_ptr并不拥有所有权
- 不能调用->和解引用*
weak_ptr为什么存在呢?
A类中有一个需求需要存储其他A类对象的信息,如果使用shared_ptr,那么在销毁时会遇到循环依赖问题,所以我们这里需要用一个不需要拥有权的指针来标记同类对象。
weak_ptr可以通过lock()函数来提升为shared_ptr(类型转换)
例1
- #include
- #include
- #include "cat.h"
- #include "cat.cpp"
- using namespace std;
-
-
- int main(int argc, char *argv[])
- {
- std::shared_ptr
p0 = make_shared("bb"); - std::weak_ptr
p1 = p0; - cout<<"p0 use_count: "<
use_count()< -
- std::shared_ptr
p2 = p1.lock(); - cout<<"p0 use_count: "<
use_count()< -
- return 0;
-
- }
输出如下,可以看出weak_ptr不会增加引用计数,将weak_ptr使用lock()函数转换后可以增加引用计数
- Constructor of Cat :bb
- p0 use_count: 1
- p0 use_count: 2
- Destructor of Cat :bb
解决循环依赖问题
更改cat.h代码如下
- #ifndef CAT_H
- #define CAT_H
- #include
- #include
- #include "cat.h"
- #include
- class Cat
- {
- public:
- Cat(std::string name);
- Cat() = default;
- ~Cat();
- void cat_info() const
- {
- std::cout << "cat info name: " << name << std::endl;
- }
- std::string get_name() const
- {
- return name;
- }
- void set_cat_name(const std::string& name)
- {
- this->name = name;
- }
- void set_friend(std::shared_ptr
c) { - m_friend = c;
- }
- private:
- std::string name{ "Mini" };
- std::shared_ptr
m_friend; - };
- #endif

此时就需要用weak_ptr来解决上图中的问题了,我们需要修改cat.h代码,如下图

此时再去运行main函数,就发现问题已经解决了

-
相关阅读:
【计算机组成原理】指令系统(一)—— 指令格式
Flutter | Stack 超出部分不响应手势的独特解决方案
CPU受限直接执行
基于Sim2Real的鸟瞰图语义分割方法
【Ascend C算子开发(入门)】——Ascend C编程模式与范式
计算机视觉全系列实战教程:(八)图像变换-点运算、灰度变换、直方图变换
Java:org.apache.commons.io包的工具类:IOUtils、FileUtils、FilenameUtils
springboot+websocket聊天室(私聊+群聊)
艾美捷ProSci丨ProSci TM4SF1 抗体解决方案
3线硬件SPI+DMA驱动 HX8347 TFT屏
-
原文地址:https://blog.csdn.net/weixin_44387095/article/details/126122486