【内存】scoped_ptr
1.初识scoped_ptr
scoped_ptr是一个与auto_ptr/unique_ptr很类似的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。但scoped_ptr的所有权更加严格,不能转让,一旦scoped_ptr获取了对象的管理权,我们就无法再从它那里收回来。scoped_ptr拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让。
2.类摘要
template<class T>
class scoped_ptr
{
private:T* px;// 原始指针scoped_ptr(scoped_ptr const &); // 拷贝构造函数私有化scoped_ptr& operator=(scoped_ptr const &); // 赋值操作私有化void operator==(scoped_ptr const &)const; // 相等操作私有化void operator!=(scoped_ptr const &)const; // 不等操作符私有化
public:explicit scoped_ptr(T* p = 0); // 显示构造函数~scoped_ptr(); // 析构函数void reset(T * p = 0); // 重置智能指针T& operator*() const; // 操作符重载T* operator->() const; // 操作符重载T* get() const; // 获得原始指针explicit operator bool() const; // 显示bool值的转换void swap(scoped_ptr & b); // 交换指针
};
template<class T> inline
bool operator==(scoped_ptr<T> const & p,boost::detail::sp_nullptr_t);
3.一个简单的模拟实现与简单应用
#include <iostream>
#include <string>
using namespace std;
template<class T>
class scoped_ptr
{
private:T* px;// 原始指针scoped_ptr(scoped_ptr const &); // 拷贝构造函数私有化scoped_ptr& operator=(scoped_ptr const &); // 赋值操作私有化void operator==(scoped_ptr const &)const; // 等号操作符重载void operator!=(scoped_ptr const &)const; // 不等号操作符重载
public:// 显示构造函数explicit scoped_ptr(T* p = 0):px(p){}// 析构函数~scoped_ptr(){delete px;px = nullptr;}// 重置智能指针的写法void reset_1(T * p = 0){if(p!=px && p!= nullptr){delete px;px = p;}}typedef scoped_ptr<T> this_type;void reset_2(T* p = 0){this_type(p).swap(*this);}// 解引用操作符重载T& operator*() const{return *px;}// 箭头操作符重载T* operator->() const{return px;}// 获得原始指针T* get() const;// 显示bool值的转换explicit operator bool() const;// 交换指针void swap(scoped_ptr & b){T* tmp = b.px;b.px = px;px = tmp;}
};
//template<class T> inline
//bool operator==(scoped_ptr<T> const & p,boost::detail::sp_nullptr_t);
class Test
{
public:void fun(){std::cout <<"line = " << __LINE__ << ", This is Test fun()" << endl;}
};
int main()
{std::cout <<"line = " << __LINE__<< ". This is a tiny scoped_ptr implementation simulation program ." << std::endl;int* p = new int(10);scoped_ptr<int> ps(p);std::cout <<"line = " << __LINE__<< ", *ps is " << *ps << endl;scoped_ptr<Test> ps1(new Test);ps1->fun();// scoped_ptr<Test> ps2 = ps1; // 不允许拷贝构造,编译时期就会报错并提示不允许这样的操作int *q = new int(100);ps.reset_1(q);std::cout <<"line = " << __LINE__<< ", *ps is " << *ps << endl;int *r = new int(1000);ps.reset_2(r);std::cout <<"line = " << __LINE__<< ", *ps is " << *ps << endl;return 0;
}
4.比较reset_1和reset_2的写法
// 重置智能指针的写法1 void reset_1(T * p = 0) {if(p!=px && p!= nullptr){delete px;px = p;} }
// 重置智能指针的写法2 typedef scoped_ptr<T> this_type; void reset_2(T* p = 0) {this_type(p).swap(*this); // this_type(p)是创建的临时的无名的局部对象,一旦脱离函数空间,对象就会调用析构函数从而被释放 }// 交换指针 void swap(scoped_ptr & b) {T* tmp = b.px;b.px = px;px = tmp; }
5.boost源码中的【type_must_be_complete】
template<class T> inline void checked_delete(T* x)
{ typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; (void) sizeof(type_must_be_complete); delete x;
}
函数总共三行语句,第三行是根本目的,很容易理解,前两行的目的就是为了所谓的安全性了。怎么个安全法呢?这两个函数是函数模版,在编译时无法确定参数的类型,而动态运行时的错误是比较棘手的,所以用这行代码:
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
来将运行时错误转变为编译期错误。这句话其实就是定义了一个固定大小的char型数组,数组名为type_must_be_complete,数组大小是多少呢?是sizeof(T)?1:-1, ?:这个三元操作符大家都很熟悉了,若sizeof(T)非0,这个表达式的值为1,即typedef了一个大小为1的char型数组,否则定义一个大小为-1的数组。数组大小还能为负数?当然不能,于是就会报错,而且是编译期错误,于是就将一个动态运行时错误在编译时就发现了。
接下来解释sizeof什么时候返回0.
C/C++语言本身似乎没有这种情况,但有些编译器会作一些扩展,比如GCC对于incomplete type使用sizeof时,会返回0.那什么又叫做incomplete type呢,就是那些声明了,但没有定义的类型,例如:
class A;
extern A a;
C++标准允许通过一个 delete 表达式删除指向不完全类的指针。如果该类有一个非平凡的析构函数,或者有一个类相关的 delete 操作符,那么其行为就是无定义的。因此编译器作了这种扩展,以将这种未定义的行为转为编译期错误,帮助程序员们及早发现。
函数的第二行语句的作用据说是为了防止编译器优化,因为编译器检测到typedef的类型未被使用到的话可能就会将其优化掉,因而第二行语句使用了这个类型,告诉编译器这个typedef是有用的,不能优化掉。至于(void)强制类型转换,是为了消除编译器对未使用sizeof返回值的警告。
6.与标准库中的unique_ptr作比较
unique_ptr是在C++标准中定义的新的智能指针,用来取代曾经的auto_ptr. 根据C++标准定义(C++11.20.7.1),unique_ptr不仅能够代理new创建的单个对象,也能够代理new[ ]创建的数组对象.
unique_ptr的基本能力与scoped_ptr相同,同样可以在作用域内管理指针,也不允许拷贝构造和拷贝赋值,但unique_ptr要比scoped ptr有更多的功能:可以像原始指针一样进行比较,可以像shared_ptr一样定制删除器,也可以安全地放入标准容器. 因此,如果读者使用的编译器支持C++11标准,那么可以毫不犹豫地使用unique_ptr来代替scoped_ptr.
当然,scoped_ptr也有它的优点,“少就是多”永远是一句至理名言,它只专注于做好作用域内的指针管理工作,含义明确,而且不允许转让指针所有权.
7.与标准库中的auto_ptr作比较
scoped_ptr的用法与auto_ptr几乎一样,大多数情况下它可以与auto_ptr相互替换,它也可以从一个auto_ptr获得指针的管理权(同时auto_ptr失去管理权).
scoped_ptr也具有auto_ptr同样的“缺陷”——不能用作容器的元素,但原因不同:auto_ptr是因为它的转移语义,而scoped_ptr则是因为不支持拷贝和赋值,不符合容器对元素类型的要求.
scoped_ptr与auto_ptr的根本性区别在于指针的所有权. auto_ptr特意被设计为指针的所有权是可转移的,可以在函数之间传递,同一时刻只能有一个auto_ptr管理指针. 它的用意是好的,但转移语义太过于微妙,不熟悉auto_ptr 特性的初学者很容易误用引发错误. 而scoped_ptr把拷贝构造函数和赋值函数都声明为私有的,拒绝了指针所有权的转让----除了scoped_ptr自己,其他任何人都无权访问被管理的指针,从而保证了指针的绝对安全.
【内存】scoped_ptr相关推荐
- 【Boost】系列02:内存管理之scoped_ptr智能指针
智能指针,stl中有auto_ptr,boost的smart_ptr库有6种: scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr和int ...
- 动态内存管理和智能指针 2.0 -- shared_ptr
shared_ptr出现原因 通过第一章的学习,我们知道不管是auto_ptr合适scoped_ptr都是存在缺陷的,于是我们必须想出一个方法既能很好的管理我们的内存,而且在使用的时候,可以多个指针指 ...
- 《C++应用程序性能优化::第五章动态内存管理》学习和理解
<C++应用程序性能优化::第五章动态内存管理>学习和理解 说明:<C++应用程序性能优化> 作者:冯宏华等 2007年版. 2010.8.29 cs_wuyg@126.com ...
- 智能指针和内存管理小结
·概述: 主要是两个库:smart_ptr库和pool库. smart_ptr库主要解决的问题是指针的内存泄漏和垃圾回收问题:pool则是解决内存分配问题. 感觉还是smart_ptr库比较好用一些, ...
- C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...
- [转] Boost智能指针——scoped_ptr
http://www.cnblogs.com/tianfang/archive/2008/09/15/1291050.html boost::scoped_ptr和std::auto_ptr非常类似, ...
- (六)boost库之内存管理shared_ptr
1.shared_ptr的基本用法 boost::shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr assert(sp.unique ...
- 【Boost】boost库中智能指针——scoped_ptr
boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include <str ...
- Boost智能指针——scoped_ptr
boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include<stri ...
最新文章
- mstsc局域网远程 要预先做的设置
- 前端笔记-js文件首行添加;号(前端小技巧)
- 制作点击文字变颜色_手机照片、视频怎样添加文字?原来很简单,4种方法一分钟搞定...
- 无锡金秋购物节 淘菜菜提供社区消费全景式服务
- 2021 前端面试经常被问到 Javascript+HTML5+CSS+ 框架问题(89 篇资料总结)
- apper安卓×××
- 利用kali Linux破解WiFi密码
- python 画三角形matli_Python实现PS滤镜特效之扇形变换效果示例
- 不用传感器的指南针android app,Android 利用方向传感器实现指南针具体步骤
- PQ分区魔术师图解教程
- 安装ie9提示未能完成安装_win7系统32位旗舰版,IE8升级IE9失败,提示未能完成安装...
- 宝塔面板安装云锁启用拦截功能全流程操作
- 薅羊毛赚钱,也可操作
- 本以为大厂无望,结果陆续收到京东/滴滴/爱奇艺offer的我迷茫了
- 计算机应用基础win,计算机应用基础(Win 7+Office 2010)
- mapbox基本使用
- 作为sigmastar代理-启明云端为你分享干货SSD201/202的QT的移植
- 小米笔记本air 13.3 2018款参数
- 解决:idea中tomcat项目改名后,原名项目启动后是新名项目的内容
- 高数——单调有界定理
热门文章
- Rasa 3.x 学习系列-Rasa [3.5.8] -2023-05-12新版本发布
- R语言处理数据——快速将多列数据首尾相连成一列
- html overflow 样式,overflow-x css属性样式
- 数据库安全保护、权限授予
- 对称密码的密钥与公钥密码的密钥
- linux 编译 cflags,python – 如何设置CFLAGS和LDFLAGS来编译pycrypto
- 我在的互联网医疗公司解散了
- rs232 python_RS232串口通讯协议解析
- php简单实现rabbitMQ消息列队(必须收藏)
- 高通平台部分英文缩写含义汇总