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,一经查实,立即删除!

相关文章

文件辅助类封装

using System;using System.Collections.Generic;using System.IO;using System.Text; namespace Manjinba.Communication.Common.Utils{ /// <summary> /// 文件辅助类 /// </summary> public class FileHelper { #region 检测指定目录是否存在 /// <summary&…

你知道吗…我不知道…你知道吗

很多你自以为知道却不知道的东西&#xff0c;你知道吗…我不知道…你知道吗…… 1.拉斯维加斯的赌场都没有钟。 2.麦当劳40%的利润来自Happy Meals的销售。 3.1996版的韦伯斯特词典有315处拼写错误。 4.每天平均有12个新生儿被交给错误的父母。 5.巧克力对于狗来说是致命的&…

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

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

通读教材第二问

我在教材第14章看到这样一段话&#xff1a;在专业时间模型中&#xff0c;一个Scrum团队负责开发项目的Product Backlog&#xff0c;同时还负责专门的时间来处理现有产品或者服务出现的问题。 请问&#xff1a;在团队项目开发中&#xff0c;专业时间模型是什么&#xff1f; 在查…

智能指针对比

智能指针对比&#xff1a; (1)、boost::shared_ptr<T> -- 基于引用计数器refcount(原子的) <1>、构造函数中refcount1&#xff0c;析构函数中refcount-1&#xff0c;当refcount的值减到为0时&#xff0c;该对象就会被销毁。 <2>、解决循环引用的问题&#x…

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

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

Sql Server 关于整表插入另一个表部分列的语法以及select 语句直接插入临时表的语法 (转帖)...

语法是这样的 :1、说明&#xff1a;复制表(只复制结构,源表名&#xff1a;a 新表名&#xff1a;b) (Access可用) 法一&#xff1a;select * into b from a where 1 <>1 法二&#xff1a;select top 0 * into b from a 2、说明&#xff1a;拷贝表(拷贝数据,源表名&#xf…

在.Net中,如何创建一个后台执行的进程?

在.Net中&#xff0c;创建一个进程十分容易。但是如果你想创建一个没有窗口的后台进程&#xff0c;你需要对ProcessStartInfo进行一些特殊的设置&#xff1a; var process new Process() { StartInfo new ProcessStartInfo("executable file name", "argument…

WorldWind Java 版学习:1、启动过程

一、JOGL使用介绍 使用 JOGL&#xff0c;需要构造GLCapabilities、GLCanvas 和 GLEventListener 的对象&#xff0c;其中 GLCapabilities 对象用于构造 GLCanvas 对象&#xff0c;将 GLCanvas 添加到相应的 Container 中用于窗口显示&#xff0c;实现 GLEventListener 中的init…

Redis pub/sub机制在实际运用场景的理解(转载)

Redis 的pub/sub机制与23种设计模式中的观察者设计模式极为类似。但Redis对于这个机制的实现更为轻便和简结&#xff0c;没有观察者模式的那么复杂的逻辑考虑而仅仅需要通过两个Redis客户端配置channel即可实现&#xff0c;因此它也仅仅做了消息的"发布"和"订阅…

第三周学习进度总结

本周学习进度&#xff1a; 第三周3月11日至3月17日每天平均写代码时间30分钟代码量630行左右所发博客数6篇本周学到的知识点对HTMLcss的常用知识点有了大概的了解&#xff0c;对java的文件操作更加熟练了下周的计划熟练掌握本周学到的知识点&#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…

dom nodeName nodeType nodeValue

1&#xff0c;nodeName属性 &#xff1a; 节点的名字。如果节点是元素节点&#xff0c;那么返回这个元素的名字。此时&#xff0c;相当于tagName属性。比如<p>aaaa</p> : 则返回 p 如果是属性节点&#xff0c;nodeName将返回这个属性的名字。如果是文本节点&…

谈谈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;显示指定数目高频单词的统计结果以及将统计结果输出至结果文件等功能。 设计实现 主程序使用无限循…

如何把Access转成SQL Server的方法介绍

1、打开“控制面板”下“管理工具”中的“数据库源”。 2、按“添加”添加一个新的数据源&#xff0c;在选择栏里选“Driver do microsoft Access (*.mdb)”&#xff0c;完成后将出现一个框&#xff0c;在“数据库源”里面输入你想写的名称&#xff0c;我取名叫“ABC”&#xf…

c/c++ 前置声明 -- typedef问题

前几天写过前置声明的问题&#xff0c;不过今天写代码时又遇到了同样的问题&#xff0c;不过是一个typedef出来的问题。 前置声明的好处很多, 比如能避免头文件互相包含的冲突, 比如有时我们在一个头文件中只需要另一个头文件的某个类型定义, 只需要对它做一下前置声明即可, 因…