- 浏览: 89898 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
林奇峰:
嗯,都是这么设计的,这是scope问题,程序是为了处理数据,为 ...
context和getApplicationContext()介绍
从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
一、boost 智能指针
智能指针是利用RAII(Resource Acquisition Is Initialization:资源获取即初始化)来管理资源。关于RAII的讨论可以参考前面的文
章。在使用boost库之前应该先下载后放在某个路径,并在VS 包含目录中添加。下面是boost 库里面的智能指针:
(一)、scoped_ptr<T>
先来看例程:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br></nobr>
|
#include<boost/scoped_ptr.hpp>
#include<iostream> usingnamespacestd; classX { public: X() { cout<<"X..."<<endl; } ~X() { cout<<"~X..."<<endl; } }; intmain(void) { cout<<"Enteringmain..."<<endl; { boost::scoped_ptr<X>pp(newX); //boost::scoped_ptr<X>p2(pp);//Error:所有权不能转移 } cout<<"Exitingmain..."<<endl; return0; } |
来稍微看一下scoped_ptr 的简单定义:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
31<br>
32<br>
33<br></nobr>
|
namespaceboost
{ template<typenameT>classscoped_ptr:noncopyable { private: T*px; scoped_ptr(scoped_ptrconst&); scoped_ptr&operator=(scoped_ptrconst&); typedefscoped_ptr<T>this_type; voidoperator==(scoped_ptrconst&)const; voidoperator!=(scoped_ptrconst&)const; public: explicitscoped_ptr(T*p=0); ~scoped_ptr(); explicitscoped_ptr(std::auto_ptr<T>p):px(p.release()); voidreset(T*p=0); T&operator*()const; T*operator->()const; T*get()const; voidswap(scoped_ptr&b); }; template<typenameT> voidswap(scoped_ptr<T>&a,scoped_ptr<T>&b); } |
与auto_ptr类似,内部也有一个T* px; 成员 ,智能指针对象pp 生存期到了,调用析构函数,在析构函数内会delete px; 如下面所说:
scoped_ptr mimics a built-in pointer except that it guarantees deletionof the object pointed to, either on destruction of the scoped_ptr or viaan
explicit reset(). scoped_ptr is a simple solution for simple needs;use shared_ptr or std::auto_ptr if your needs are more complex.
从上面的话可以得知当调用reset() 函数时也能够释放堆对象,如何实现的呢?
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br></nobr>
|
voidreset(T*p=0)//neverthrows
{ BOOST_ASSERT(p==0||p!=px);//catchself-reseterrors this_type(p).swap(*this); } voidswap(scoped_ptr&b)//neverthrows { T*tmp=b.px; b.px=px; px=tmp; } |
typedef scoped_ptr<T> this_type; 当调用pp.reset(),reset 函数构造一个临时对象,它的成员px=0, 在swap 函数中调换 pp.px 与
(this_type)(p).px, 即现在pp.px = 0; //解绑
临时对象接管了裸指针(即所有权可以交换),reset 函数返回,栈上的临时对象析构,调用析构函数,进而delete px;
另外拷贝构造函数和operator= 都声明为私有,故所有权不能转移,且因为容器的push_back 函数需要调用拷贝构造函数,故也不能
将scoped_ptr 放进vector,这点与auto_ptr 相同(不能共享所有权)。此外,还可以使用 auto_ptr 对象 构造一个scoped_ptr 对象:
scoped_ptr( std::auto_ptr<T> p ): px( p.release() );
由于scoped_ptr是通过delete来删除所管理对象的,而数组对象必须通过deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果
要管理数组对象需要使用boost::scoped_array类。
boost::scoped_ptr和std::auto_ptr的功能和操作都非常类似,如何在他们之间选取取决于是否需要转移所管理的对象的所有权(如是否需要作为
函数的返回值)。如果没有这个需要的话,大可以使用boost::scoped_ptr,让编译器来进行更严格的检查,来发现一些不正确的赋值操作。
(二)、shared_ptr<T>
An enhanced relative of scoped_ptr with reference counted copy semantics.The object pointed to is deleted when the last
shared_ptr
pointing to it is destroyed or reset.
先来看例程:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
31<br>
32<br>
33<br>
34<br></nobr>
|
#include<boost/shared_ptr.hpp>
#include<iostream> usingnamespacestd; classX { public: X() { cout<<"X..."<<endl; } ~X() { cout<<"~X..."<<endl; } }; intmain(void) { cout<<"Enteringmain..."<<endl; boost::shared_ptr<X>p1(newX); cout<<p1.use_count()<<endl; boost::shared_ptr<X>p2=p1; //boost::shared_ptr<X>p3; //p3=p1; cout<<p2.use_count()<<endl; p1.reset(); cout<<p2.use_count()<<endl; p2.reset(); cout<<"Exitingmain..."<<endl; return0; } |
图示上述程序的过程也就是:
再深入一点,看源码,shared_ptr 的实现 比 scoped_ptr 要复杂许多,涉及到多个类,下面就不贴完整源码,看下面的类图:
执行boost::shared_ptr<X>p1(newX);
这一行之后:
而执行 p1.use_count(); 先是pn.use_count(); 接着pi_ != 0? pi_->use_count(): 0; return use_count_; 即返回1.
接着执行boost::shared_ptr<X>p2=p1;
本想跟踪shared_ptr 的拷贝构造函数,在当行设置断点后F11直接跳过了,说明是shared_ptr类没有实现拷贝构造函数,使用的是编译器默认的拷
贝构造函数,那如何跟踪呢?如果你的C++基础比较好,可以想到拷贝构造函数跟构造函数一样,如果有对象成员是需要先构造对象成员的(这一点
也可以从调用堆栈上看出),故可以在shared_count 类的拷贝构造函数设置断点,然后就可以跟踪进去,如下的代码:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br></nobr>
|
// shared_count
shared_count(shared_countconst&r):pi_(r.pi_)//nothrow
{ if(pi_!=0)pi_->add_ref_copy(); } // sp_counted_base
voidadd_ref_copy() { BOOST_INTERLOCKED_INCREMENT(&use_count_); } |
故p2.pn.pi_ 也指向 唯一的一个 sp_counted_impl_p 对象,且use_count_ 增1.
再者,shared_ptr 类的默认拷贝构造函数是浅拷贝,故现在p2.px 也指向 X.
由于p2 和 p1 共享一个sp_counted_impl_p 对象,所以此时无论打印p2.use_count(); 还是 p1.use_count(); 都是2。
接着执行p1.reset();
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br></nobr>
|
// shared_ptr
voidreset()//neverthrowsin1.30+
{ this_type().swap(*this); } voidswap(shared_ptr<T>&other)//neverthrows { std::swap(px,other.px); pn.swap(other.pn); } |
this_type() 构造一个临时对象,px = 0, pn.pi_ = 0; 然后swap交换p1 与 临时对象的成员,即现在p1.px = 0; p1.pn.p1_ = 0; 如上图。
reset 函数返回,临时对象需要析构,但跟踪时却发现直接返回了,原因跟上面的一样,因为shared_ptr 没有实现析构函数,调用的是默认的析构函
数,与上面拷贝函数同样的道理,可以在shared_count 类析构函数设置断点,因为pn 是对象成员,故析构函数也会被调用。如下代码:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br></nobr>
|
//shared_count
~shared_count()//nothrow
{ if(pi_!=0)pi_->release(); } // sp_counted_base voidrelease()//nothrow { if(BOOST_INTERLOCKED_DECREMENT(&use_count_)==0) { dispose(); weak_release(); } } |
现在use_count_ 减为1,但还不为0,故dispose(); 和weak_release(); 两个函数没有被调用。当然此时打印 p2.use_count() 就为1 了。
最后 p2.reset(); 跟p1.reset(); 同样的流程,只不过现在执行到release 时,use_count_ 减1 为0;需要继续执行dispose(); 和
weak_release(); 如下代码:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br></nobr>
|
//sp_counted_impl_p virtualvoiddispose()//nothrow { boost::checked_delete(px_); } //sp_counted_base voidweak_release()//nothrow { if(BOOST_INTERLOCKED_DECREMENT(&weak_count_)==0) { destroy(); } } virtualvoiddestroy()//nothrow { deletethis; } |
在check_delete 中会 delete px_; 也就是析构 X。接着因为weak_count_ 减1 为0, 故执行destroy(); 函数里面delete this; 即析构自身
(sp_counted_impl_p 对象是在堆上分配的)。
说到这里,我们也可以明白,即使最后没有调用p2.reset(); 当p2 栈上对象生存期到, 需要调用shared_ptr 类析构函数,进而调用shared_count 类析
构函数,所以执行的结果也是跟reset() 一样的,只不过少了临时对象this_type()的构造。
总结一下:
和前面介绍的boost::scoped_ptr相比,boost::shared_ptr可以共享对象的所有权,因此其使用范围基本上没有什么限制(还是有一些需要遵循的
使用规则,下文中介绍),自然也可以使用在stl的容器中。另外它还是线程安全的,这点在多线程程序中也非常重要。
boost::shared_ptr并不是绝对安全,下面几条规则能使我们更加安全的使用boost::shared_ptr:
-
避免对shared_ptr所管理的对象的直接内存管理操作,以免造成该对象的重释放
-
shared_ptr并不能对循环引用的对象内存自动管理(这点是其它各种引用计数管理内存方式的通病)。
- 不要构造一个临时的shared_ptr作为函数的参数。
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br></nobr>
|
voidf(shared_ptr<int>,int);
intg(); voidok() { shared_ptr<int>p(newint(2)); f(p,g()); } voidbad() { f(shared_ptr<int>(newint(2)),g()); } |
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
31<br>
32<br>
33<br>
34<br>
35<br>
36<br>
37<br>
38<br>
39<br>
40<br>
41<br>
42<br>
43<br>
44<br>
45<br>
46<br>
47<br></nobr>
|
#include<boost/shared_ptr.hpp>
#include<iostream> usingnamespacestd; classParent; classChild; typedefboost::shared_ptr<Parent>parent_ptr; typedefboost::shared_ptr<Child>child_ptr; classChild { public: Child() { cout<<"Child..."<<endl; } ~Child() { cout<<"~Child..."<<endl; } parent_ptrparent_; }; classParent { public: Parent() { cout<<"Parent..."<<endl; } ~Parent() { cout<<"~Parent..."<<endl; } child_ptrchild_; }; intmain(void) { parent_ptrparent(newParent); child_ptrchild(newChild); parent->child_=child; child->parent_=parent; return0; } |
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br></nobr>
|
namespaceboost
{ template<typenameT>classweak_ptr { public: template<typenameY> weak_ptr(constshared_ptr<Y>&r); weak_ptr(constweak_ptr&r); template<classY> weak_ptr&operator=(weak_ptr<Y>&&r); template<classY> weak_ptr&operator=(shared_ptr<Y>const&r); ~weak_ptr(); boolexpired()const; shared_ptr<T>lock()const; }; } |
&&
is
new in C++11, and it signifies that the function accepts anRValue-Reference--
that is, a reference to an argument that is about
to be destroyed. //也就是说函数接受左值引用,也就是引用着的变量可以被修改
两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用智能指针。
强引用与弱引用:
强引用,只要有一个引用存在,对象就不能释放
弱引用,并不增加对象的引用计数(实际上是不增加use_count_, 会增加weak_count_);但它能知道对象是否存在
通过weak_ptr访问对象的成员的时候,要提升为shared_ptr
如果存在,提升为shared_ptr(强引用)成功
如果不存在,提升失败
对于上述的例子,只需要将Parent 类里面的成员定义改为如下,即可解决循环引用问题:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br></nobr>
|
classParent
{ public: boost::weak_ptr<parent>child_; }; |
因为此例子涉及到循环引用,而且是类成员引用着另一个类,涉及到两种智能指针,跟踪起来难度很大,我也没什么心情像分析
shared_ptr 一样画多个图来解释流程,这个例子需要解释的代码远远比shared_ptr 多,这里只是解释怎样使用,有兴趣的朋友自
己去分析一下。
下面再举个例子说明lock() 和 expired() 函数的用法:
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
31<br>
32<br>
33<br>
34<br>
35<br>
36<br>
37<br>
38<br>
39<br>
40<br>
41<br>
42<br>
43<br>
44<br>
45<br>
46<br>
47<br>
48<br>
49<br>
50<br>
51<br>
52<br>
53<br>
54<br>
55<br></nobr>
|
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp> #include<boost/scoped_array.hpp> #include<boost/scoped_ptr.hpp> #include<iostream> usingnamespacestd; classX { public: X() { cout<<"X..."<<endl; } ~X() { cout<<"~X..."<<endl; } voidFun() { cout<<"Fun..."<<endl; } }; intmain(void) { boost::weak_ptr<X>p; boost::shared_ptr<X>p3; { boost::shared_ptr<X>p2(newX); cout<<p2.use_count()<<endl; p=p2; cout<<p2.use_count()<<endl; /*boost::shared_ptr<X>*/ p3=p.lock(); cout<<p3.use_count()<<endl; if(!p3) cout<<"objectisdestroyed"<<endl; else p3->Fun(); } /*boost::shared_ptr<X>p4=p.lock(); if(!p4) cout<<"objectisdestroyed"<<endl; else p4->Fun();*/ if(p.expired()) cout<<"objectisdestroyed"<<endl; else cout<<"objectisalived"<<endl; return0; } |
从输出可以看出,当p = p2; 时并未增加use_count_,所以p2.use_count() 还是返回1,而从p 提升为 p3,增加了
use_count_, p3.use_count() 返回2;出了大括号,p2 被析构,use_count_ 减为1,程序末尾结束,p3 被析构,
use_count_ 减为0,X 就被析构了。
参考 :
C++ primer 第四版
Effective C++ 3rd
C++编程规范
http://www.cnblogs.com/TianFang/
相关推荐
【Boost智能指针详解:scoped_ptr、shared_ptr与weak_ptr】 智能指针是C++中用来自动管理动态分配内存的对象,它可以确保在适当的时间释放内存,以防止内存泄漏。Boost库提供了一组智能指针类型,包括scoped_ptr、...
在C++11及更高版本中,智能指针(如`std::unique_ptr`,`std::shared_ptr`和`std::scoped_ptr`)被引入来更好地管理动态内存,因此理解如何在这些指针上实现序列化至关重要。 首先,让我们关注`std::unique_ptr`。`...
- **定义**:`scoped_ptr`是最简单的智能指针之一,它的设计目的是在其生命周期结束时自动释放其所管理的对象。 - **特点**: - `scoped_ptr`的效率接近于内置指针。 - 它不能用于标准库容器。 - 不适用于需要...
本文将详细介绍 STL 中的智能指针,包括 std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost::intrusive_ptr 等七种智能指针。 一、简介 ...
Boost库提供了一种名为`boost::scoped_ptr`的智能指针,它是一种简单的智能指针类型,适用于管理单个非托管对象。与`std::auto_ptr`相似,`boost::scoped_ptr`在对象生命周期结束时会自动调用`delete`释放内存。 `...
Boost库中的`smart_ptr`提供了一系列强大而灵活的智能指针类型,这些智能指针极大地简化了C++中资源管理的复杂度,提高了程序的安全性和可靠性。通过使用Boost智能指针,开发者可以专注于业务逻辑的编写,而不必担心...
Boost智能指针是由C++标准委员会库工作组支持的Boost组织开发的一套智能指针解决方案,主要包括五种智能指针模板类:`scoped_ptr`、`scoped_array`、`shared_ptr`、`shared_array`以及`weak_ptr`。 ##### 1. `...
3. shared_ptr:支持的转型有:static_pointer_cast<T>、const_pointer_cast<T>、dynamic_pointer_cast<T>,返回的结果是shared_ptr,并能保证这些指针的引用计数正确。 其他组件 1. ptime:用来表示时间点,相当...
1. **std::auto_ptr**:在C++98和C++03中,std::auto_ptr是最早的智能指针之一,但在C++11中被弃用,因为它不满足现代C++的内存管理需求。std::auto_ptr具有所有权的概念,一个std::auto_ptr对象一旦被赋值给另一个...
此外,`scoped_ptr` 还提供了一系列方法来管理指针,如 `get()`、`->`、`()`、`reset()` 和 `swap()` 等。 ##### 3.2 `scoped_array` 和 `scoped_ptr_malloc` 实现原理 `scoped_array` 和 `scoped_ptr_malloc` 与 ...
一、简介 由于 C++ 语言没有自动...包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr。你可能会想,如此多的智能指
Boost库是C++编程语言的一个开源库集合,由一系列高质量、跨平台的库组成,旨在提升C++的标准库功能并提供现代编程范式。这个库广泛应用于许多领域,包括图形处理、数学计算、并发编程、序列化、测试框架等。对于想...
**Smart_ptr**库是Boost中最知名的库之一,提供了多种智能指针类型,旨在解决C++中资源管理的问题。智能指针能够自动管理其指向的对象的生命周期,避免内存泄漏等问题。 - **Scoped_ptr**: 是最简单的智能指针类型...
1. Smart_ptr:这一部分主要讨论了智能指针,包括scoped_ptr、scoped_array、shared_ptr、shared_array、intrusive_ptr和weak_ptr等。智能指针可以帮助程序员管理内存,防止内存泄漏。在C++标准库中并没有直接提供...
3. **智能指针**:Boost库提供了`shared_ptr`和`weak_ptr`,它们在C++11中被纳入标准库,解决了原始指针可能导致的内存管理问题。此外,还有`unique_ptr`,它在C++11之前就存在于Boost库中。 4. **容器和算法**:...
C++ Boost库是一个著名的开源库,它为C++标准库提供了许多补充功能,极大地增强了C++的灵活性和表现力。Boost库包含众多模块,如时间日期处理、内存管理、智能指针等,使得C++程序员可以更加高效地开发高质量的软件...