C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常
shared_ptr和new结合使用
- shared_ptr<double> p1;
- shared_ptr<int> p2(new int(42)); // p2指向一个值为42的int
接受指针参数的智能指针构造函数是explicit的,因此,我们不能将一个内置指针隐式的转换为一个智能指针,必须使用直接初始化形式:
- shared_ptr<int> p1 = new int(1024); // 错误,必须使用直接初始化形式
- shared_ptr<int> p2(new int(1024));
p1的初始化隐式的要求编译器用一个new返回的int* 来初始化一个shared_ptr。由于我们不能进行内置指针到智能指针间的隐式转换,因此这条初始化语句是错误的。同样的,一个返回值为shared_ptr的函数不能在其返回语句中转换一个普通指针:
- shared_ptr<int> clone(int p) {
- return new int(p); // 错误,隐式转换为shared_ptr
- }
我们必须将shared_ptr显示绑定到一个想要返回的指针上:
- shared_ptr<int> clone(int p) {
- return shared_ptr<int>(new int(p));
- }
shared_ptr<T> p(q) | p管理内置指针q所指向的对象,q必须指向new分配的内存,且能转换为T* 类型 |
shared_ptr<T> p(u) | p从unique_ptr u那里接管了对象的所有权,将u置为空 |
shared_ptr<T> p(q, d) | p接管了内置指针q所指向的对象的所有权,q必须能转换为T*类型,p将使用可调用对象d来代替delete |
shared_ptr<T> p(p2, d) | p是shared_ptr p2的拷贝,唯一的区别是p将用可调用对象d来代替delete |
p.reset() | 若p是唯一指向其对象的shared_ptr,reset操作会释放此对象。 |
p.reset(q) | 若传递了参数q,会令p指向q,否则将p置为空 |
p.reset(q. d) | 若还传递了参数d,则使用可调用对象d来代替delete |
- 不要混合使用普通指针和智能指针
- void process(shared_ptr<int> ptr) {
- // 使用ptr
- } // ptr离开作用域,被销毁
process的参数是值传递形式的,因此在调用process函数时,会拷贝shared_ptr,拷贝一个shared_ptr会增加引用计数,假设原来的shared_ptr只有自身一个引用者,在调用process函数时,其引用技术变为2,在process结束后,ptr被释放,引用计数变为1。因此,当局部变量ptr被销毁时,ptr指向的内存并不会被释放。
- shared_ptr<int> p(new int(42)); // 引用计数为1
- process(p); //拷贝p,在函数结束前引用计数为2,函数执行结束后,引用计数变为1
- int i = *p; // i == 42
我们前面说到,不能将一个内置指针隐式转换为一个shared_ptr,因此,我们不能将一个内置指针直接传递给process函数,但可以传递给它一个临时的shared_ptr,这个shared_ptr使用一个内置指针显示构造的:
- int* x(new int(1024));
- process(x); // 错误,不能将一个int*转换为一个shared_ptr,因位构造函数时explicit的
- process(shared_ptr<int>(x)); // 合法的,但x所管理的内存会被释放
- int j = *x; // 错误,x是一个空悬指针!
- 不要用get成员函数初始化另一个智能指针或为只能指针赋值
- shared_ptr<int> p(new int(1024));
- int* q = p.get();
- { // 新的作用域
- shared_ptr<int> p1(p);
- } // 作用域结束,p1被销毁,p1所管理的对象被释放
- int foo = *p; // 未定义,p指向的内存已经被释放了
● get将指针的访问权限传递给代码,只有在确定代码不会delete指针的情况下,才能使用get。特别的,永远用get的返回值初始化一个智能指针或给一个智能指针赋值。
- 其他的shared_ptr操作
- p = new int(1024); // p是一个shared_ptr类型, 发生错误,不能将一个指针赋予shared_ptr
- p.reset(new int(1024)); // p指向一个新对象
unique操作: 如果一个shared_ptr对象唯一指向它所管理的内存对象,则返回true。
- if (! p.unique()) //如果p补是它所管理对象的唯一引用者,则为它重新分配
- p.reset(new int(100));
- *p += newVal; // 现在p是唯一的用户,可以改变对象的值
智能指针和异常
- void f() {
- shared_ptr<int> sp(new int(42));
- // 抛出异常,未在f中捕获
- // 函数结束后shared_ptr正确释放资源
- }
上面的代码中,无论是正常结束或发生异常,shared_ptr都会释放资源。
- void f() {
- int* ip = new int(42);
- // 发生异常,且在f中未捕获
- delete ip;
- }
在上面的代码中,如果在资源被释放前发生异常,且未捕获,那么new所分配的内存资源就不会被释放。
- 一个智能指针的例子,使用我们自己的删除器
- struct destination; // 表示我们正在连接什么
- struct connection; // 使用连接所需的信息
- connection connect(destination*); // 打开连接
- void disconnect(connection); // 关闭给定的连接
- void f (destination& d) {
- // 获得一个连接,记住使用完要关闭它
- connection c = connect(d);
- // 使用连接
- // 如果在f结束之前忘记调用disconnect,就无法关闭c了
- }
如果connection有一个析构函数,就可以在f结束之后关闭c,但是connection并没有析构函数,我们可以使用shared_ptr来管理这些对象。默认情况下,shared_ptr使用delete进行释放内存,为了使用shared_ptr来管理connection,我们需要提供自己的删除器:
- void end_connection(connection* p) { disconnect(*p); }
当创建一个connection的shared_ptr时,可以传递一个指向删除器函数的参数:
- void f (destination& d) {
- connection c = connect(&d);
- shared_ptrM<connection> p(&c, end_connection);
- // 使用连接
- // f结束后,connection被正确关闭
- }
p被销毁时,它不会对自己保存的指针使用delete,而是调用end_connection。
- 智能指针的陷阱:
C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常的更多相关文章
- C++ Primer : 第十二章 : 动态内存之shared_ptr类实例:StrBlob类
StrBlob是一个管理string的类,借助标准库容器vector,以及动态内存管理类shared_ptr,我们将vector保存在动态内存里,这样就能在多个对象之间共享内存. 定义StrBlob类 ...
- C++ Primer : 第十二章 : 动态内存之shared_ptr类
在C++中,动态内存是的管理是通过一对运算符来完成的:new ,在动态内存中为对象分配空间并返回一个指向该对象的指针,delete接受一个动态对象的指针,销毁该对象,并释放该对象关联的内存. 动态内 ...
- C++ Primer : 第十二章 : 动态内存之动态数组
动态数组的分配和释放 new和数组 C++语言和标准库提供了一次分配一个对象数组的方法,定义了另一种new表达式语法.我们需要在类型名后跟一对方括号,在其中指明要分配的对象的数目. int* arr ...
- C++ Primer : 第十二章 : 动态内存之动态内存管理(new和delete)
C++语言定义了两个运算符来分配和释放动态内存:运算符new分配内存,运算符delete释放new分配的内存. 运算符new和delete 使用new动态分配和初始化对象 在自由空间分配的内存是无名的 ...
- C++ Primer : 第十二章 : 动态内存之unique_ptr和weak_ptr
unique_ptr 一个unique_ptr拥有它所管理的对象,与shared_ptr不同,unique_ptr指向的对象只能有一个用户.当unique_ptr被销毁后,它所指向的对象也被销毁. 定 ...
- C++ Primer : 第十二章 : 动态内存之allocator类
标准库allocator类定义在头文件 <memory>中.它帮助我们将内存分配和构造分离开来,它分配的内存是原始的.未构造的. 类似vector,allocator也是一个模板类,我们在 ...
- C++ Primer 5th 第12章 动态内存
练习12.1:在此代码的结尾,b1 和 b2 各包含多少个元素? StrBlob b1; { StrBlob b2 = {"a", "an", "th ...
- Linux内核设计与实现 总结笔记(第十二章)内存管理
内核里的内存分配不像其他地方分配内存那么容易,内核的内存分配不能简单便捷的使用,分配机制也不能太复杂. 一.页 内核把页作为内存管理的基本单位,尽管处理器最小寻址坑是是字或者字节.但是内存管理单元MM ...
- C++Primer 第十二章
//1.标准库提供了两种智能指针类型来管理动态对象,均定义在头文件memory中,声明在std命名空间. // shared_ptr:允许多个指针指向同一个对象. // unique_ptr:独占所指 ...
随机推荐
- 设置groupBox背景透明
步骤:属性-BackColor-WEB面板-Transparent
- Hibernate 的配置文件
Hibernate 配置文件 •Hibernate 配置文件主要用于配置数据库连接和 Hibernate 运行时所需的各种属性 •每个 Hibernate 配置文件对应一个 Configuration ...
- 站在K2角度审视流程--任务的独占与释放
应用场景一:某件事情由A.B两人(或者更多人)完成,任务开始后,两人随时可以处理任务,只需有一人处理完成,此事情即可结束. 应用场景二:某件事情由A.B两人(或者更多人)完成,任务开始后,两人随时可以 ...
- 可以创建专业的客户端/服务器视频会议应用程序的音频和视频控件LEADTOOLS Video Conferencing SDK
LEADTOOLS Video Streaming Module控件为您创建一个自定义的视频会议应用程序和工具提供所有需要的功能.软件开发人员可以使用Video Streaming Module SD ...
- Power Point已经检测到你的显卡可能无法正确配置
Microsoft PowerPoint打开ppt时提示信息 PowerPoint已检测到你的显卡可能无法正确配置最佳的幻灯片播放体验(“Power Point has detected that y ...
- opencv中的Mat类型
Mat类型主要是跟matlab中的数据类型一样.故用起来很方便. Mat最大的优势跟STL很相似,都是对内存进行动态的管理,不需要之前用户手动的管理内存,对于一些大型的开发,有时候投入的lpImage ...
- DP重新学
白书上的DP讲义:一 二 DAG上的dp 不要好高骛远去学这种高端东西,学了也写不对,剩下的几天把基本的dp和搜索搞下,就圆满了.不要再学新算法了,去九度把现有的算法写个痛. 学了数位DP和记忆搜索, ...
- druid连接池配置
本人使用的是springMVC框架,以下是我的配置: step1,配置数据源(applicationContext-resource.xml中): <bean id="cc_ds&qu ...
- Note_Master-Detail Application(iOS template)_05_ YJYMasterViewController.m
// YJYMasterViewController.m #import "YJYMasterViewController.h" #import "YJYDetailV ...
- Design Patterns
经典的<设计模式>一书归纳出23种设计模式,本文按<易学设计模式>一书归纳分类如下:1.创建型模式 前面讲过,社会化的分工越来越细,自然在软件设计方面也是如此,因此对象的创建和 ...