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相关推荐

  1. 【Boost】系列02:内存管理之scoped_ptr智能指针

    智能指针,stl中有auto_ptr,boost的smart_ptr库有6种: scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr和int ...

  2. 动态内存管理和智能指针 2.0 -- shared_ptr

    shared_ptr出现原因 通过第一章的学习,我们知道不管是auto_ptr合适scoped_ptr都是存在缺陷的,于是我们必须想出一个方法既能很好的管理我们的内存,而且在使用的时候,可以多个指针指 ...

  3. 《C++应用程序性能优化::第五章动态内存管理》学习和理解

    <C++应用程序性能优化::第五章动态内存管理>学习和理解 说明:<C++应用程序性能优化> 作者:冯宏华等 2007年版. 2010.8.29 cs_wuyg@126.com ...

  4. 智能指针和内存管理小结

    ·概述: 主要是两个库:smart_ptr库和pool库. smart_ptr库主要解决的问题是指针的内存泄漏和垃圾回收问题:pool则是解决内存分配问题. 感觉还是smart_ptr库比较好用一些, ...

  5. C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr

    1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...

  6. [转] Boost智能指针——scoped_ptr

    http://www.cnblogs.com/tianfang/archive/2008/09/15/1291050.html boost::scoped_ptr和std::auto_ptr非常类似, ...

  7. (六)boost库之内存管理shared_ptr

    1.shared_ptr的基本用法 boost::shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr assert(sp.unique ...

  8. 【Boost】boost库中智能指针——scoped_ptr

    boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include <str ...

  9. Boost智能指针——scoped_ptr

    boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include<stri ...

最新文章

  1. mstsc局域网远程 要预先做的设置
  2. 前端笔记-js文件首行添加;号(前端小技巧)
  3. 制作点击文字变颜色_手机照片、视频怎样添加文字?原来很简单,4种方法一分钟搞定...
  4. 无锡金秋购物节 淘菜菜提供社区消费全景式服务
  5. 2021 前端面试经常被问到 Javascript+HTML5+CSS+ 框架问题(89 篇资料总结)
  6. apper安卓×××
  7. 利用kali Linux破解WiFi密码
  8. python 画三角形matli_Python实现PS滤镜特效之扇形变换效果示例
  9. 不用传感器的指南针android app,Android 利用方向传感器实现指南针具体步骤
  10. PQ分区魔术师图解教程
  11. 安装ie9提示未能完成安装_win7系统32位旗舰版,IE8升级IE9失败,提示未能完成安装...
  12. 宝塔面板安装云锁启用拦截功能全流程操作
  13. 薅羊毛赚钱,也可操作
  14. 本以为大厂无望,结果陆续收到京东/滴滴/爱奇艺offer的我迷茫了
  15. 计算机应用基础win,计算机应用基础(Win 7+Office 2010)
  16. mapbox基本使用
  17. 作为sigmastar代理-启明云端为你分享干货SSD201/202的QT的移植
  18. 小米笔记本air 13.3 2018款参数
  19. 解决:idea中tomcat项目改名后,原名项目启动后是新名项目的内容
  20. 高数——单调有界定理

热门文章

  1. Rasa 3.x 学习系列-Rasa [3.5.8] -2023-05-12新版本发布
  2. R语言处理数据——快速将多列数据首尾相连成一列
  3. html overflow 样式,overflow-x css属性样式
  4. 数据库安全保护、权限授予
  5. 对称密码的密钥与公钥密码的密钥
  6. linux 编译 cflags,python – 如何设置CFLAGS和LDFLAGS来编译pycrypto
  7. 我在的互联网医疗公司解散了
  8. rs232 python_RS232串口通讯协议解析
  9. php简单实现rabbitMQ消息列队(必须收藏)
  10. 高通平台部分英文缩写含义汇总