C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常
来源:互联网 发布:java异常分类 编辑:程序博客网 时间:2024/05/22 09:45
shared_ptr和new结合使用
一个shared_ptr默认初始化为一个空指针。我们也可以使用new返回的指针来初始化一个shared_ptr:
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)); }
默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete来释放它所关联的对象。 我们也可以把智能指针绑定到其他类型的指针上,但是我们必须提供自己的删除操作来替代delete:
- 不要混合使用普通指针和智能指针
shared_ptr可以协调对象的析构,但这仅限于自身的拷贝,因此,我们尽量用make_shared而不要用new的原因就在这。这样,我们在分配对象的同时将shared_ptr与之绑定,从而避免了将同一块内存绑定到多个独立创建的shared_ptr上。
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:
shared_ptr<int> p(new int(42)); // 引用计数为1process(p); //拷贝p,在函数结束前引用计数为2,函数执行结束后,引用计数变为1int 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是一个空悬指针!
在这段程序中shared_ptr是临时构造的,因此在这个shared_ptr只有ptr一个引用者,在函数结束后,ptr的析构函数被执行,它所管理的内存被释放,因为和x所管理的内存相同,因此x将成为一个空悬指针,解引用x将会发生错误,这样的行为是未定义的。
- 不要用get成员函数初始化另一个智能指针或为只能指针赋值
智能指针类定义了一个get的成员函数,该成员函数返回一个内置指针,指向智能指针管理的对象。此函数为了向不使用智能指针的代码传递一个普通指针,使用get返回的指针的代码不能delete此指针。
将一个智能指针绑定到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操作
reset操作:
p = new int(1024); // p是一个shared_ptr类型, 发生错误,不能将一个指针赋予shared_ptrp.reset(new int(1024)); // p指向一个新对象
reset会更新引用计数,如果需要的话,会释放p指向的对象。reset经常unique一起使用,来控制多个shared_ptr共享的对象。
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所分配的内存资源就不会被释放。
- 一个智能指针的例子,使用我们自己的删除器
例如有一个C和C++都能使用的简单的网络库:
struct destination; // 表示我们正在连接什么struct connection; // 使用连接所需的信息connection connect(destination*); // 打开连接void disconnect(connection); // 关闭给定的连接void f (destination& d) { // 获得一个连接,记住使用完要关闭它 connection c = connect(d); // 使用连接 // 如果在f结束之前忘记调用disconnect,就无法关闭c了}
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。
- 智能指针的陷阱:
● 不使用相同的内置指针值初始化(或reset)多个智能指针
● 不delete get()返回的指针
● 不使用get() 初始化或reset另一个智能指针
● 如果使用get() 返回的指针,当最后一个对应的智能指针销毁后,该指针就变为无效了
● 如果智能指针管理的不是new分配的内存,记得传递给它一个删除器
0 0
- C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常
- C++ Primer : 第十二章 : 动态内存之shared_ptr类
- 《C++ Primer》读书笔记第十二章-1-动态内存与智能指针
- c++智能指针(三)之shared_ptr和new结合使用
- C++primer学习:智能指针与动态内存(1)
- C++Primer学习:智能指针与动态内存(2)
- C++Primer学习:动态内存与智能指针(3)
- C++ Primer : 第十二章 : 动态内存之shared_ptr类实例:StrBlob类
- c++ primer(第五版)学习笔记及习题答案代码版(第十二章)动态内存与智能指针
- C++ Primer : 第十二章 : 动态内存之动态内存管理(new和delete)
- shared_ptr和weak_ptr智能指针结合使用的一个实例
- C++:智能指针之shared_ptr
- 【足迹C++primer】39、动态内存与智能指针(1)
- 【足迹C++primer】39、动态内存与智能指针(2)
- 【足迹C++primer】39、动态内存与智能指针(3)
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- C++11智能指针之shared_ptr的使用(1)
- iOS开发 自定义一个全屏的蒙板(导航栏也能遮挡住)
- Oracle基本查询 一
- Gamebryo 游戏引擎分析(一)整体设计
- 使用hiredis提供的接口访问redis中的ZSeT对象
- 最大熵模型中的数学推导
- C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常
- MillerRabin
- An error has occurred. See error log for more details. java.lang.NullPointerException
- SSDB:高性能数据库服务器
- HDU4135
- xtrabackup备份mysql数据库
- jQuery的deferred对象详解
- hbase实现分页查询
- CSting分配空间