1、POCO C++库学习和分析 -- 内存管理 (二) 3. SharedPtr SharedPtr是Poco库中基于引用计数实现的另外一种智能指针。同AutoPtr相比,Poco::SharedPtr主要用于为没有实现引用计数功能的类(换句话说,也就是该类本身不是引用计数对象)提供引用计数服务,实现动态地址的自动回收。 可以这么说,Poco::AutoPtr是使用继承关系来实现的智能指针,而Poco::SharedPtr是聚合方法实现的智能指针。 3.1 SharedPtr的类图 首先来看一下SharedPtr的类图:
2、 从类图中可以看到SharedPtr是对引用计数和原生指针封装。其中有成员指针_ptr,指向任意类型的C;同时还存在一个引用计数对象的指针_pCounter,指向任意一个实现了引用计数的类。当然在Poco库中提供了ReferenceCount的默认实现,类ReferenceCounter。 比较类ReferenceCounter和AutoPtr中依赖的类RefCountedObject,可以发现其实现相同,本质上就是一个东西。Poco库中之所以把两者分开,我想是为了明确的表示类与类之间的关系。ReferenceCounter用于组合,而RefCountedObjec
3、t用于继承。
SharedPtr在实现模板的时候,还预留了RP参数,这是一个释放策略,用于调整SharedPtr在释放数组和单个对象之间不同策略的转换。
[cpp] view plaincopy
1. template
4、 3.2 SharedPtr操作符和值语义 1. Poco::SharedPtr同样支持关系操作符==, !=, <, <=, >, >=; 2. 当Poco::SharedPtr中原生指针为空时,使用解引用操作符“*”或者"->",Poco::SharedPtr会抛出一个NullPointerException 异常。 3. Poco::SharedPtr同样支持全值语义,包括默认构造函数,拷贝构造函数,赋值函数并且同样可以用于各类容器(如std::vector 和 std::map) [cpp] view plaincopy
5、 1. SharedPtr& operator = (C* ptr) 2. { 3. return assign(ptr); 4. } 5. 6. SharedPtr& assign(C* ptr) 7. { 8. if (get() != ptr) 9. { 10. RC* pTmp = new RC; 11. release(); 12. _pCounter = pTmp; 13. _ptr = ptr; 14. }
6、 15. return *this; 16. } 17. 18. void release() 19. { 20. poco_assert_dbg (_pCounter); 21. int i = _pCounter->release(); 22. if (i == 0) 23. { 24. RP::release(_ptr); 25. _ptr = 0; 26. 27. delete _pCounter; 28.
7、 _pCounter = 0;
29. }
30. }
注意,在SharedPtr赋值操作符"="中的操作,对于原生指针_ptr的操作策略是交换,而引用计数对象_pCounter的策略是先new一个,再交换。
4. 可以用SharedPtr::isNull()和SharedPtr::operator ! () 去检查内部的原生指针是否为空。
3.3 SharedPtr和Cast类型转换
同普通指针类似,Poco::SharedPtr支持cast操作符。这在 template
8、SharedPtr
9、 (assume class Sub: public Super)
6. /// SharedPtr
10、tr
11、haredPtr& operator = (const SharedPtr
12、 SharedPtr tmp(ptr);
13. swap(tmp);
14. }
15. return *this;
16. }
17.
18. template
13、er->duplicate(); 22. } 下面是关于操作符的一个例子: [cpp] view plaincopy 1. #include "Poco/SharedPtr.h" 2. class A 3. { 4. public: 5. virtual ~A() 6. {} 7. }; 8. class B: public A 9. { 10. }; 11. class C: public A 12. { 13. }; 14. int main(int argc,
14、char** argv) 15. { 16. Poco::SharedPtr pA; 17. Poco::SharedPtr pB(new B); 18. pA = pB; // okay, pB is a subclass of pA 19. pA = new B; 20. // pB = pA; // will not compile 21. pB = pA.cast();
15、 // okay
22. Poco::SharedPtr
16、aredPtr时是不允许的。这时候两个SharedPtr都会声称拥有对象的所有权,将导致程序crash。在AutoPtr中虽然不推荐如此做,但提供了一个解决方案,使用以下函数,并至"shared=true"。 [cpp] view plaincopy 1. AutoPtr::AutoPtr(C* pObject, bool shared); 2. AutoPtr& AutoPtr::assign(C* pObject, bool shared); 对于Poco::SharedPtr来说,最好的方法是一旦用SharedPtr获取到对象所有权后,就不要再试图
17、使用指向对象的原生指针。
下面是SharedPtr的一个例子:
[cpp] view plaincopy
1. #include "Poco/SharedPtr.h"
2. #include
18、SharedPtr
19、BAD BAD BAD: multiple owners -> multiple delete 12. p2 = p1; // rc == 2 13. std::string::size_type len = p1->length(); // dereferencing with -> 14. std::cout << *p1 << std::endl; // der
20、eferencing with *
15. return 0;
16. }
17. // rc == 0 -> deleted
3.5 SharedPtr和数组
默认的SharedPtr删除策略是指删除对象。如果创建对象时使用数组,并把它委托给SharedPtr,必须使用对应数组删除策略。这时候SharedPtr的模板参数中ReleasePolicy应该使用类ReleaseArrayPolicy。
下面是对应的另一个例子:
[cpp] view plaincopy
1. template
21、class ArrayReleasePolicy
3. {
4. public:
5. static void release(C* pObj)
6. /// Delete the object.
7. /// Note that pObj can be 0.
8. {
9. delete [] pObj;
10. }
11. };
12. char* pStr = new char[100];
13. SharedPtr






