[关闭]
@coolwyj 2014-12-05T13:04:55.000000Z 字数 2430 阅读 2347

智能指针(1)

C++


参考:百度百科


概念

智能指针是存储指向动态分配对象指针的类。除了能够在适当的时间自动删除指向的对象外,他们的工作机制很像C++的内置指针。智能指针在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象。他们也可以用于跟踪被多用户共享的动态分配对象。


原理

智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。

每次创建类的新对象时,初始化指针并将引用计数置为1;
当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;
调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。

实现引用计数有两种经典策略:一是引入辅助类,二是使用句柄类。

方案一

定义一个单独的具体类(RefPtr)来封装指针和相应的引用计数。由于这个类只是用于对类TestPtr中的成员指针ptr进行了封装,无其它用途,所以把引用计数类RefPtr的所有成员均定义为private,并把类TestPtr声明为它的友元类,使TestPtr类可以访问RefPtr类。

这种技术的一个实例为:写时拷贝(Copy-On-Write)

这种方案的缺点是每个含有指针的类的实现代码中都要自己控制引用计数,比较繁琐。特别是当有多个这类指针时,维护引用计数比较困难。

示例代码如下:

  1. class RefPtr
  2. {
  3. friend class TestPtr;
  4. int*ptr;
  5. size_t count;
  6. RefPtr(int*p):ptr(p),count(1){}
  7. ~RefPtr(){
  8. delete ptr;
  9. }
  10. };
  11. class TestPtr
  12. {
  13. public:
  14. TestPtr(int*p):ptr(new RefPtr(p)){}
  15. TestPtr(const TestPtr &src):ptr(src.ptr){
  16. ++ptr->count;
  17. }
  18. TestPtr& operator=(const TestPtr &rhs){
  19. ++rhs.ptr->count;
  20. if(--ptr->count==0)
  21. delete ptr;
  22. ptr=rhs.ptr;
  23. return *this;
  24. }
  25. ~TestPtr(){
  26. if(--ptr->count==0)
  27. delete ptr;
  28. }
  29. private:
  30. RefPtr* ptr;
  31. };

方案二

为了避免上面方案中每个使用指针的类自己去控制引用计数,可以用一个类把指针封装起来。封装好后,这个类对象可以出现在用户类使用指针的任何地方,表现为一个指针的行为。我们可以像指针一样使用它,而不用担心普通成员指针所带来的问题,我们把这样的类叫句柄类。在封装句柄类时,需要申请一个动态分配的引用计数空间,指针与引用计数分开存储。

实现示例如下:

  1. #include<iostream>
  2. #include<stdexcept>
  3. using namespace std;
  4. #define TEST_SMARTPTR
  5. class Stub{
  6. public:
  7. void print(){
  8. cout<<"Stub:print"<<endl;
  9. }
  10. ~Stub(){
  11. cout<<"Stub:Destructor"<<endl;
  12. }
  13. };
  14. template<typename T>
  15. class SmartPtr{
  16. public:
  17. SmartPtr(T* p=0):ptr(p),pUse(new size_t(1)){}
  18. SmartPtr(const SmartPtr &src):ptr(src.ptr),pUse(src.pUse){
  19. ++*pUse;
  20. }
  21. SmartPtr& operator=(const SmartPtr &rhs){
  22. ++*rhs.pUse;
  23. decrUse();
  24. ptr=rhs.ptr;
  25. pUse=rhs.pUse;
  26. return *this;
  27. }
  28. // as right value
  29. T* operator->(){
  30. if(ptr)
  31. return ptr;
  32. throw std::runtime_error("access through NULL pointer");
  33. }
  34. // as left value
  35. const T* operator->()const{
  36. if(ptr)
  37. return ptr;
  38. throw std::runtime_error("access through NULL pointer");
  39. }
  40. T& operator*(){
  41. if(ptr)
  42. return*ptr;
  43. throw std::runtime_error("dereference of NULL pointer");
  44. }
  45. const T& operator*()const{
  46. if(ptr)
  47. return*ptr;
  48. throw std::runtime_error("dereference of NULL pointer");
  49. }
  50. ~SmartPtr(){
  51. decrUse();
  52. #ifdef TEST_SMARTPTR
  53. std::cout<<"SmartPtr:Destructor"<<std::endl;//fortesting
  54. #endif
  55. }
  56. private:
  57. void decrUse(){
  58. if(--*pUse==0){
  59. delete ptr;
  60. delete pUse;
  61. }
  62. }
  63. T* ptr;
  64. size_t* pUse;
  65. };
  66. int main()
  67. {
  68. try{
  69. SmartPtr <Stub> t;
  70. t->print();
  71. }catch(const exception &err){
  72. cout<<err.what()<<endl;
  73. }
  74. SmartPtr <Stub> t1(new Stub);
  75. SmartPtr <Stub> t2(t1);
  76. SmartPtr <Stub> t3(new Stub);
  77. t3=t2;
  78. t1->print();
  79. (*t3).print();
  80. return 0;
  81. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注