C++智能指针

在C++中通过new/delete进行内存分配和释放,但是实际编码过程中可能由于程序员的疏忽导致内存泄漏问题的出现。 在Java中GC(垃圾回收机制)进行内存管理。C++11同样增加了内存管理功能,这就是智能指针。

  • 智能指针本质上是一个模板类,一般使用的这个类的对象,而不是指针
  • 智能指针体现在内存释放问题上,用智能指针管理new的对象,将不在需要手动delete

实现原理

智能指针是存储指向动态分配(堆区)对象指针的类,内部通过引用计数实现对管理对象内存的监控,每使用一次引用计数+1,每析构一次引用计数减1,当减为0,释放所指向管理对象的内存。

通过RAII机制,用于生存期的控制,当离开智能智能的作用域会自动销毁动态分配的对象,防止发生内存泄漏问题。

智能指针的分类

C++11提供了三种智能指针

  • std::shared_ptr 共享的智能指针
  • std::unique_ptr 独占的智能指针
  • std::weak_ptr 弱引用的智能指针,它不共享指针,不能操作资源,是用来shared_ptr的

下面详细介绍下智能指针

  • shared_ptr
    get()函数:返回数据的指针的引用
    use_count() : 返回管理对象的智能指针个数
    swap() : 交换两个智能指针管理的对象
    reset() : 重置智能指针对象
    针对部分场景需要自己手动添加删除器去释放对象内存

  • weak_ptr
    弱引用指针,不会累计计数
    weak_ptr只能通过shared_ptr或者weak_ptr来构造
    主要应用场景:为了解决shared_ptr循环引用内存导致无法释放问题
    不能使用*访问,可以使用->取值
    通过成员函数lock()获取shared_ptr对象然后在访问数据

  • unique_ptr
    禁止拷贝和赋值 独占型
    任何时候unique_ptr操作管理对象,永远只有一个有效
    可以通过move()函数转交所有权
    reset函数结合release函数移交所有权

以下对于三种类型分别举例:

  • shared_ptr
#include <iostream>
#include <string>
#include <memory>
using namespace std;class MyPerson {public:MyPerson(int age) :age(age) { cout << "MyPerson构造函数被调用!" << endl; }MyPerson(){cout << "MyPerson无参构造函数被调用" << endl;}~MyPerson() { cout << "MyPerson析构函数被调用!" << endl; }void print(){cout << "MyPerson的年龄:" << age << endl;}
private:int age;
};//这里智能指针类对象作为入参,会发送拷贝构造所以use_count智能指针数会+1
//如果传入引用就不会到导致use_count增加
void printPersonData(shared_ptr<MyPerson> pMyPerson)
{pMyPerson->print();cout << "管理MyPerson对象的指针数:" << pMyPerson.use_count() << endl;
}int main()
{//针对基本数据类型shared_ptr<int> pInt(new int(111));//访问数据cout << *pInt << endl;cout << "使用get()获取数据:" << *pInt.get() << endl;//use_count返回对象的指针数cout << "管理对象的指针数:" << pInt.use_count() << endl;shared_ptr<int> pInt2(pInt); //使用拷贝构造函数cout << "管理对象的指针数:" << pInt.use_count() << endl;cout << "管理对象的指针数:" << pInt2.use_count() << endl;shared_ptr<int> pInt3;if (!pInt3){cout << "空智能指针对象" << endl;}pInt3 = pInt2;cout << "管理对象的指针数:" << pInt3.use_count() << endl;//使用swap交换两个智能指针对象shared_ptr<int> aa(new int(11));shared_ptr<int> bb(new int(22));aa.swap(bb);cout << "交换后" << endl;cout << "aa=" << *aa << "\tbb=" << *bb << endl;bb.reset(new int(123));  //重置cout << "*bb=" << *bb << endl;//针对自定义数据类型//初始化shared_ptr<MyPerson> pMyPerson(new MyPerson(10));//访问数据pMyPerson->print();cout << "管理MyPerson对象的指针数:" << pMyPerson.use_count() << endl;printPersonData(pMyPerson);//shared_ptr智能指针管理的对象会自动释放内存system("pause");return 0;
}

结果分析:
1、使用shared_ptr智能指针管理自定义对象可以使用->访问对象的成员函数(shared_ptr智能指针类内部实现了重定义operator->)
2、使用shared_ptr智能指针管理的对象会自动释放内存,无需手动释放(针对于new创建内存)
3、使用use_count()返回管理对象的智能指针个数

111
使用get()获取数据:111
管理对象的指针数:1
管理对象的指针数:2
管理对象的指针数:2
空智能指针对象
管理对象的指针数:3
交换后
aa=22   bb=11
*bb=123
MyPerson构造函数被调用!
MyPerson的年龄:10
管理MyPerson对象的指针数:1
MyPerson的年龄:10
管理MyPerson对象的指针数:2

针对如下场景

不支持创建连续内存
shared_ptr<MyPerson> pMyPerson2(new MyPerson(10)[4]);

如果想要实现上面常见则自己需要在创建智能指针对象类时添加删除器(自己手动写释放内存过程)`

//带删除器写法; 自己写释放内存过程shared_ptr<MyPerson> pMyPerson2(new MyPerson[4], [](MyPerson* array) {delete[] array; });
  • weak_ptr
#include <iostream>
#include <string>
#include <memory>
using namespace std;class MyPerson {public:MyPerson(int age) :age(age) { cout << "MyPerson构造函数被调用!" << endl; }MyPerson(){cout << "MyPerson无参构造函数被调用" << endl;}~MyPerson() { cout << "MyPerson析构函数被调用!" << endl; }void print(){cout << "MyPerson的年龄:" << age << endl;}
private:int age;
};int main()
{//针对自定义数据类型//初始化shared_ptr<MyPerson> pMyPerson(new MyPerson(10));//访问数据pMyPerson->print();cout << "管理MyPerson对象的指针数:" << pMyPerson.use_count() << endl;//weak_ptr初始化只能通过shared_ptr或者weak_ptrweak_ptr< MyPerson> pWeakPtr(pMyPerson);//通过weak_ptr不会导致引用计数增加cout << "管理MyPerson对象的指针数:" << pMyPerson.use_count() << endl;//*pWeakPtr.print(); weak_ptr不存在这种访问方式//通过lock()获取shared_ptr对象pWeakPtr.lock().get()->print();system("pause");return 0;
}
  • unique_ptr
#include <iostream>
#include <string>
#include <memory>
using namespace std;class MyPerson {public:MyPerson(int age) :age(age) { cout << "MyPerson构造函数被调用!" << endl; }MyPerson(){cout << "MyPerson无参构造函数被调用" << endl;}~MyPerson() { cout << "MyPerson析构函数被调用!" << endl; }void print(){cout << "MyPerson的年龄:" << age << endl;}
private:int age;
};int main()
{//针对自定义数据类型//初始化unique_ptr<MyPerson> pMyPerson(new MyPerson(111));//unique_ptr不能拷贝和赋值 如下://unique_ptr<MyPerson> pMyPerson2(pMyPerson);unique_ptr<MyPerson> pMyPerson3;//pMyPerson3 = pMyPerson;//move移交所有权后原来的则不能继续使用pMyPerson3 = move(pMyPerson);pMyPerson3->print();//reset重置对象pMyPerson.reset(new MyPerson(20));unique_ptr<MyPerson> pMyPerson4;pMyPerson4.reset(pMyPerson3.release());system("pause");return 0;
}

C++智能指针之01相关推荐

  1. android系统核心机制 基础(01)智能指针wp sp

    该系列文章总纲链接:android 系统核心机制基础 系列文章目录 本章关键点总结 & 说明: 以上是本模块的导图,整体概括了智能指针的几个要点,引用计数,弱转强,flag标志意义以及Ligh ...

  2. 智能指针引用计数器版

    前些日子,写过一个普通的智能指针,模拟的是boost中的auto_ptr,今天又写了一个关于boost中的share_ptr,引用计数器智能指针,感觉还行,功能基本实现,设计思想基本上是这么一回事,智 ...

  3. Android智能指针

    智能指针的目标   在使用指针的时候容易出现的问题不外乎下面几个.首先,指针在使用之前都必须初始化,这个还算容易解决,在创建指针变量的时候同步初始化就好了:第二个问题就是经常忘记delete,就我的经 ...

  4. c++ 智能指针_详解 C++ 11 中的智能指针

    C/C++ 语言最为人所诟病的特性之一就是存在内存泄露问题,因此后来的大多数语言都提供了内置内存分配与释放功能,有的甚至干脆对语言的使用者屏蔽了内存指针这一概念.这里不置贬褒,手动分配内存与手动释放内 ...

  5. ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析...

    Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...

  6. 智能指针手表_智能手表如何检测体内的药物水平

    智能指针手表 By Hanae Armitage 由Hanae Armitage A new wearable technology that straps right onto your wrist ...

  7. bartender一行打印两个二次开发_C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树...

    作者:apocelipes  链接:https://www.cnblogs.com/apocelipes/p/10758692.html 二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不 ...

  8. 五点讲述C++智能指针的点点滴滴

    (在学习C/C++或者想要学习C/C++可以加我们的学习交流QQ群:712263501群内有相关学习资料) 0.摘要 本文先讲了智能指针存在之前C++面临的窘境,并顺理成章地引出利用RAII技术封装普 ...

  9. 关于 智能指针 的线程安全问题

    先说结论,智能指针都是非线程安全的. 多线程调度智能指针 这里案例使用的是shared_ptr,其他的unique_ptr或者weak_ptr的结果都是类似的,如下多线程调度代码: #include ...

最新文章

  1. [Spring cloud 一步步实现广告系统] 20. 系统运行测试
  2. vi 打开不同编码的文件
  3. 招募 | 清华大学计算机系副教授黄民烈招募NLP方向博士后
  4. 深入探讨C++中的引用(转)
  5. 聊聊HTTPS和SSL/TLS协议
  6. 【Python学习日志】 - Numpy包
  7. mysql 动态索引_MySQL的索引
  8. JSP 中的几种注释
  9. 如何消灭 Android 应用中的广告?
  10. Thinkpad E431 解决无线网卡无法开启
  11. Python collections.Counter()用法
  12. python处理excel多重筛选
  13. ubuntu18.04修改mac地址
  14. [Sass常见用法] Css代码的Sass打开方式
  15. 微信小程序 php 手机授权登录
  16. poj 3975hdu 1850 (nim)
  17. 服务器电源系统,服务器电源系统于新一代数据中心设计的基础意义
  18. 代驾小程序源码开发这3大功能不可少
  19. CenterNet 后处理过程及源码解析
  20. 界面与程序分离---MIS开发新方法

热门文章

  1. 尚硅谷和黑马java,全网首发!
  2. iPhone14也将支持拍月亮了,然而这可能是技术工程师的功劳
  3. vue 二级路由嵌套和二级路由高亮问题
  4. mongodb 分片集群安装 -- 二进制文件安装
  5. YOLOv7-Pose尝鲜,基于YOLOv7的关键点模型测评
  6. 数字图像处理(入门篇)十四 透视变换
  7. 4款国产良心软件,完全免费,其中两款一直被误认为外国人开发
  8. 2017杭州云栖大会 智能客服专场预热 — 用心服务客户,用云助力客服
  9. 一天设计100张海报?so easy
  10. 普鸥知产|亚马逊品牌备案被判“滥用行为”无法备案如何解决?