当前位置: 首页 > news >正文

[C++] Boost智能指针——boost::scoped_ptr(使用及原理分析)

简介

     boost::scoped_ptr是一个比较简单的智能指针,它能保证在离开作用域之后它所管理对象能被自动释放。下面这个例子将介绍它的使用:

 1 #include <iostream>
 2 #include <boost/scoped_ptr.hpp>
 3 
 4 using namespace std;
 5 
 6 class Book
 7 {
 8 public:
 9     Book()
10     {
11         cout << "Creating book ..." << endl;
12     }
13 
14     ~Book()
15     {
16         cout << "Destroying book ..." << endl;
17     }
18 };
19 
20 int main()
21 {   
22     cout << "=====Main Begin=====" << endl;
23     {
24         boost::scoped_ptr<Book> myBook(new Book());
25     }
26     cout << "===== Main End =====" << endl;
27 
28     return 0;
29 }

     运行结果:

     可以看出:当myBook离开了它的作用域之后,它所管理的Book对象也随之销毁。

 

特点——不能共享控制权

     scoped_ptr不能通过其他scoped_ptr共享控制权,因为在scoped_ptr类的内部将拷贝构造函数=运算符重载定义为私有的。我们看下scoped_ptr类的定义就清楚了:

 1 namespace boost
 2 {
 3     template<typename T> class scoped_ptr : noncopyable
 4     {
 5     private:
 6 
 7         T *px;
 8 
 9         scoped_ptr(scoped_ptr const &);
10         scoped_ptr &operator=(scoped_ptr const &);
11 
12         typedef scoped_ptr<T> this_type;
13 
14         void operator==( scoped_ptr const & ) const;
15         void operator!=( scoped_ptr const & ) const;
16     public:
17         explicit scoped_ptr(T *p = 0);
18         ~scoped_ptr();
19 
20         explicit scoped_ptr( std::auto_ptr<T> p ): px( p.release() );
21         void reset(T *p = 0);
22 
23         T &operator*() const;
24         T *operator->() const;
25         T *get() const;
26 
27         void swap(scoped_ptr &b);
28     };
29 
30     template<typename T>
31     void swap(scoped_ptr<T> &a, scoped_ptr<T> &b);
32 }

 

     下面这段代码中的注释部分打开会造成编译失败:

 1 #include <iostream>
 2 #include <boost/scoped_ptr.hpp>
 3 
 4 using namespace std;
 5 
 6 class Book
 7 {
 8 public:
 9     Book()
10     {
11         cout << "Creating book ..." << endl;
12     }
13 
14     ~Book()
15     {
16         cout << "Destroying book ..." << endl;
17     }
18 };
19 
20 int main()
21 {   
22     cout << "=====Main Begin=====" << endl;
23     {
24         boost::scoped_ptr<Book> myBook(new Book());
25         //boost::scoped_ptr<Book> myBook1(myBook);    // Error: scoped_ptr的拷贝构造函数私有
26         //boost::scoped_ptr<Book> myBook2 = myBook;   // Error: scoped_ptr的=运算符重载私有
27     }
28     cout << "===== Main End =====" << endl;
29 
30     return 0;
31 }

 

    所以,scoped_ptr不能用在标准库的容器中,因为容器中的push_back操作需要调用scoped_ptr的=运算符重载函数,结果就是会导致编译失败。

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <boost/scoped_ptr.hpp>
 5 
 6 using namespace std;
 7 
 8 class Book
 9 {
10 private:
11     string name_;
12 
13 public:
14     Book(string name) : name_(name)
15     {
16         cout << "Creating book " << name_ << " ..." << endl;
17     }
18 
19     ~Book()
20     {
21         cout << "Destroying book " << name_ << " ..." << endl;
22     }
23 };
24 
25 int main()
26 {   
27     cout << "=====Main Begin=====" << endl;
28     {
29         boost::scoped_ptr<Book> myBook(new Book("「1984」"));
30         vector<boost::scoped_ptr<Book>> vecScoped;
31         //vecScoped.push_back(myBook);   // Error: push_back操作内部调用了scoped_ptr的=运算符重载函数
32     }
33     cout << "===== Main End =====" << endl;
34 
35     return 0;
36 }

 

编译检查=万无一失?

     虽然我们无法通过scoped_ptr的拷贝构造函数和=运算符重载函数共享控制权。那如果将一个对象交给多个scoped_ptr来管理会怎样?

 1 #include <iostream>
 2 #include <boost/scoped_ptr.hpp>
 3 
 4 using namespace std;
 5 
 6 class Book
 7 {
 8 public:
 9     Book()
10     {
11         cout << "Creating book ..." << endl;
12     }
13 
14     ~Book()
15     {
16         cout << "Destroying book ..." << endl;
17     }
18 };
19 
20 int main()
21 {   
22     cout << "=====Main Begin=====" << endl;
23     {
24         Book * book = new Book();
25         boost::scoped_ptr<Book> myBook(book);
26         boost::scoped_ptr<Book> myBook1(book);
27     }
28     cout << "===== Main End =====" << endl;
29 
30     return 0;
31 }

      我们发现编译没报错,但是运行时出错了,如下:

     之所以会这样是因为每个scoped_ptr对象都保存了自己所管理对象指针px,scoped_ptr对象在离开自己作用域时会调用了自身的析构函数,在析构函数内部会调用delete px,当多个scoped_ptr管理同一个对象时,那么在它们离开作用域之后,势必会多次调用delete以释放它们所管理的对象,从而造成程序运行出错。

 

其他接口

     虽然scoped_ptr不能转移控制权,但是它们可以交换共享权。就以下面的代码举个例子:

 1 #include <iostream>
 2 #include <string>
 3 #include <boost/scoped_ptr.hpp>
 4 
 5 using namespace std;
 6 
 7 class Book
 8 {
 9 private:
10     string name_;
11 
12 public:
13     Book(string name) : name_(name)
14     {
15         cout << "Creating book " << name_ << " ..." << endl;
16     }
17 
18     ~Book()
19     {
20         cout << "Destroying book " << name_ << " ..." << endl;
21     }
22 };
23 
24 int main()
25 {   
26     cout << "=====Main Begin=====" << endl;
27     {
28         boost::scoped_ptr<Book> myBook(new Book("「1984」"));
29         boost::scoped_ptr<Book> myBook1(new Book("「A Song of Ice and Fire」"));
30         myBook.swap(myBook1);
31     }
32     cout << "===== Main End =====" << endl;
33 
34     return 0;
35 }

      运行结果:

     根据栈的特性,应该是后面构造的scoped_ptr对象先销毁(从而销毁了它们所管理的对象),正是因为我们对两个智能指针的控制权进行交换之后,才出现了这种相反的结果。

 

     此外,在scoped_ptr离开作用域之前也是可以显式销毁它们所管理的对象的。调用它的reset方法即可。请看下面例子:

 1 #include <iostream>
 2 #include <string>
 3 #include <boost/scoped_ptr.hpp>
 4 
 5 using namespace std;
 6 
 7 class Book
 8 {
 9 private:
10     string name_;
11 
12 public:
13     Book(string name) : name_(name)
14     {
15         cout << "Creating book " << name_ << " ..." << endl;
16     }
17 
18     ~Book()
19     {
20         cout << "Destroying book " << name_ << " ..." << endl;
21     }
22 };
23 
24 int main()
25 {   
26     cout << "=====Main Begin=====" << endl;
27     {
28         boost::scoped_ptr<Book> myBook(new Book("「1984」"));
29         myBook.reset();
30         cout << "After reset ..." << endl;
31     }
32     cout << "===== Main End =====" << endl;
33 
34     return 0;
35 }

      运行结果:

     可以看出:程序在输出“After reset ...”之前已经完成了对所管理对象的释放。

 

总结(摘自《超越C++标准库:Boost库导论》)

     使用裸指针来写异常安全和无错误的代码是很复杂的。使用智能指针来自动地把动态分配对象的生存期限制在一个明确的范围之内,是解决这种问题的一个有效的方法,并且提高了代码的可读性、可维护性和质量。scoped_ptr明确地表示被指物不能被共享和转移。当一个动态分配的对象被传送给 scoped_ptr, 它就成为了这个对象的唯一的拥有者。因为scoped_ptr几乎总是以自动变量或数据成员来分配的,因此它可以在离开作用域时正确地销毁,从而在执行流由于返回语句或异常抛出而离开作用域时,总能释放它所管理的内存。

     在以下情况时使用scoped_ptr:

  • 在可能有异常抛出的作用域里使用指针
  • 函数里有几条控制路径
  • 动态分配对象的生存期应被限制于特定的作用域内
  • 异常安全非常重要时(始终如此!)

 

参考

  • http://www.cnblogs.com/sld666666/archive/2010/12/16/1908265.html
  • Björn Karlsson:Beyond the C++ Standard Library: An Introduction to Boost(《超越C++标准库:Boost库导论》)

 

(完)

转载于:https://www.cnblogs.com/helloamigo/p/3572533.html

相关文章:

  • ie63像素bug原因及解决办法不使用hack
  • Cmake编译成静态库
  • EMOS 配置及优化
  • 视频行业缩略词解释
  • PHP:WampServer下如何安装多个版本的PHP、mysql、apache
  • MongoDB笔记十八——GridFS
  • Linux系统调用--getrlimit()与setrlimit()函数详解
  • 组合模式
  • C#的变迁史 - C# 2.0篇
  • bind编译安装及压力测试
  • 曲演杂坛--权限不足引发的错误提示“服务器无法继续执行该事务”
  • Puppet dashboard 安装
  • 微服务理论之二:面向微服务架构与传统架构、SOA对比,以及云化对比
  • typedef用法和与define的区别
  • rsync服务器同步配置参数
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • Angular2开发踩坑系列-生产环境编译
  • CSS 提示工具(Tooltip)
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • PAT A1092
  • windows-nginx-https-本地配置
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 工作中总结前端开发流程--vue项目
  • 回顾2016
  • 利用DataURL技术在网页上显示图片
  • 判断客户端类型,Android,iOS,PC
  • 项目管理碎碎念系列之一:干系人管理
  • 昨天1024程序员节,我故意写了个死循环~
  • ​linux启动进程的方式
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​业务双活的数据切换思路设计(下)
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #### go map 底层结构 ####
  • #{}和${}的区别是什么 -- java面试
  • (39)STM32——FLASH闪存
  • (4)(4.6) Triducer
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (二)hibernate配置管理
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (未解决)macOS matplotlib 中文是方框
  • .Net Web项目创建比较不错的参考文章
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .Net7 环境安装配置
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • /bin、/sbin、/usr/bin、/usr/sbin
  • ?php echo ?,?php echo Hello world!;?
  • [ solr入门 ] - 利用solrJ进行检索
  • [<死锁专题>]
  • [8481302]博弈论 斯坦福game theory stanford week 1
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [Angular] 笔记 8:list/detail 页面以及@Input