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

简介

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

复制代码

 1 #include <iostream>2 #include <boost/scoped_ptr.hpp>3 4 using namespace std;5 6 class Book7 {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 boost2 {3     template<typename T> class scoped_ptr : noncopyable4     {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 Book7 {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 Book9 {
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 Book7 {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 Book8 {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 Book8 {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库导论》)

 

(完)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c# 读取记事本txt文档到DataTable中

有时候我们仅仅需要用到简单的几个数据,没有必要在数据库中建立单独的表去存储这些数据然后去连接数据库等等。 例如&#xff1a;我们的程序中只需要给几个人定时发送邮件&#xff0c;而这几个人的邮件地址则可以放到txt文档中,然后读取出来即可。 从txt读取出来的数据&#xf…

魔兽争霸3地图(WarIII Maps):梦若流星

魔兽争霸3地图&#xff08;WarIII Maps&#xff09;&#xff1a;梦若流星梦若流星游戏类型&#xff1a;RPG通关时间&#xff1a;30分钟流星蝴蝶剑后传&#xff0c;即使孟星魂想独善其身&#xff0c;也未必就能如愿………………为了更好的体验游戏&#xff0c;请在在“选项—声音…

flash特效原理:图片滑动放大效果(2)

flash特效原理&#xff1a;图片滑动放大效果(1) http://blog.csdn.net/hero82748274/archive/2009/10/22/4715312.aspx 最近看了一些关于动态注册点更加的办法&#xff0c;顺手牵羊把他下载了&#xff0c;感觉挺好用。再把一个倒影类给下载了&#xff0c;结合上次一个做法&…

Windows Phone 7实现图片数据绑定

Windows Phone 7实现图片数据绑定 首先我们使用ListBox来显示多张图片&#xff0c;然后在建立一个单独的页面来显示单独的一张图片。 1.我们建立一个Picture.xaml的页面&#xff0c;并使用ListBox控件来显示多张图片的信息。&#xff0c;示例代码如下&#xff1a; <Grid x:N…

类前置声明的使用

今天在写代码时&#xff0c;遇到了是否需要加头文件的问题&#xff0c;看到这个博客之后收益匪浅&#xff0c;因此转载该篇文章。 转载&#xff1a;https://www.jianshu.com/p/9768175387b6 首先我们看这样一个示例程序: 以上代码中,类CY中有个CX类型的数据成员,我们需要在CY…

谈谈CLOSE_WAIT

TCP 有很多连接状态&#xff0c;每一个都够聊十块钱儿的&#xff0c;比如我们以前讨论过 TIME_WAIT 和 FIN_WAIT1&#xff0c;最近时不时听人提起 CLOSE_WAIT&#xff0c;感觉有必要梳理一下。 所谓 CLOSE_WAIT&#xff0c;借用某位大牛的话来说应该倒过来叫做 WAIT_CLOSE&…

Windows Phone 7 自适应键盘输入

在移动设备上由于空间比较小&#xff0c;例如手机的屏幕&#xff0c;所以显示完整的输入键盘不行或者不美观。因此程序需要处理键盘的呈现&#xff0c;比如一个Textbox控件&#xff0c;我们只想输入数字&#xff0c;那么如果不处理还会显示字母的输入界面&#xff0c;这样即占用…

201673020127 词频统计软件项目报告

需求分析 从给定文本中得出单词频数的统计数据。 功能设计 首要功能是统计指定文本中的词频&#xff0c;保证其健壮性。在此基础上还需实现显示对指定单词的统计结果&#xff0c;显示指定数目高频单词的统计结果以及将统计结果输出至结果文件等功能。 设计实现 主程序使用无限循…

TextTree - 文本资料收集轻量级工具

你有没有收集资料的习惯? 如果有久而久之你会发现资料越来越多,找起来很麻烦. 过去我收集资料,单个文件,资料太多不好找,就分成多个文件. 文件一多,有时会乱放,结果结果经常满硬盘搜索,就为了找一个文件,于是我后来就集中放在同一个文件夹. 文件夹里的文件一多,看文件名也是眼…

Spring Boot分布式系统实践【扩展1】shiro+redis实现session共享、simplesession反序列化失败的问题定位及反思改进...

前言 调试之前请先关闭Favicon配置 spring:favicon:enabled: false 不然会发现有2个请求&#xff08;如果用nginx 浏览器调试的话&#xff09; 序列化工具类【fastjson版本1.2.37】 public class FastJson2JsonRedisSerializer implements RedisSerializer { public static fin…

svn: E200033: database is locked, executing statement 'RELEASE   s0' 问题解决办法

前几天svn迁移到其他路径之后&#xff0c;今天早上更新代码时&#xff0c;出现了下面的问题&#xff1a; svn: E200033: database is locked, executing statement RELEASE s0 稍后执行了 svn cleanup svn up 等命令之后都不好使 网上查找资料尝试整了一遍之后是可以的&…

Getting Started with the Table Component

为什么80%的码农都做不了架构师&#xff1f;>>> Home Wiki Getting Started with the Table Component Getting Started with the Table Component Table of Contents [hide] Creating Your First Report using the Table Component Step 1: Create a datasourc…

.NET Framewrok 4.0新增类库

转载于:https://www.cnblogs.com/tweet/archive/2010/02/08/1665805.html

在构造函数/析构函数中调用virtual函数带来的影响

在构造函数/析构函数中调用virtual函数&#xff0c;那么调用的一定是本类中的virtual函数。 先看一段代码&#xff1a; #include<iostream>class Base { public:Base() {print();}~Base() {print();}virtual void print() {std::cout << "Base::print"…

编程之美-第3章 结构之法

3.1. 字符串移位包含问题 方法1: 分别对字符串进行循环移1位,2位,3位…,来判断给定的字符串是否是其中一个字串. 复杂度是O(n^3) 方法2: 这也是一种利用空间换时间的方法. 代码如下, 为了简便实现,采用了C库中的字符串操作函数: #if 0 /** 3.1*/ bool isRotate(char *s1,char* …

InnoDB一棵B+树可以存放多少行数据?

一个问题&#xff1f; InnoDB一棵B树可以存放多少行数据&#xff1f;这个问题的简单回答是&#xff1a;约2千万。为什么是这么多呢&#xff1f;因为这是可以算出来的&#xff0c;要搞清楚这个问题&#xff0c;我们先从InnoDB索引数据结构、数据组织方式说起。 我们都知道计算…

调整路由的AD值

实验&#xff1a;调整路由的AD值【实验名称】调整路由的AD值 (注意&#xff1a;PT有可能不支持distance 99 192.168.1.2 0.0.0.0这条命令&#xff0c;所以我们做实验的时候最好用小凡模拟器)【实验目的】通过调整路由的管理距离值&#xff0c;实现路由的管理和控制【实验背景】…

MySQL索引的一些问题

MySQL索引的一些问题 注意&#xff1a;本文基于MySQL的InnoDB引擎说明。 一、什么是最左前缀原则 对于该表&#xff0c;如果按照name字段来建立索引的话&#xff0c;采用B树结构&#xff0c;大概的索引如下&#xff1a; 如果要进行模糊查找&#xff0c;查找name 以“张"…

大家狂欢吧,我的Google帐号悲剧了

大家狂欢吧&#xff0c;我的Google帐号悲剧了 今早开始&#xff0c;鄙人在Google Code上突然被强行杯具&#xff0c;出现如下图。 最无奈的是询问Google Code管理组后得到回复如下。 然后管理员就睡觉去了|||…… 继续等待中&#xff0c;能恢复的话我会发个解决心得以警后人&am…

为Mac OS X添加用Firefox搜索服务

为Mac OS X添加用Firefox搜索服务 在Mac OS X上&#xff0c;Firefox这种移植过来的程序往往不提供服务&#xff0c;比如只有safari才能利用服务搜索&#xff0c;经过一番实验终于自己做了一个服务&#xff1a; 第一步&#xff0c;打开Automator 第二部&#xff0c;新建一个服务…