淺談auto_ptr智能指針

引入智能指針:
智能指針的實現原理:
資源分配即初始化RAII(Resource Acquisition Is Initialization):

定義一個類來封裝資源的分配和釋放,在構造函數完成資源的分配
和初始化,在析構函數完成資源的清理,可以保證資源的正確初始化和釋放。

實現機制:利用類的構造和析構函數(釋放資源)是由編譯器自動調用的。
智能指針:
1.管理指針執行對象的釋放問題。

2.可以像指針一樣使用。

在c++標準庫里主要有四個智能指針:

C++四種智能指針auto_ptr、unique_ptr、shared_ptr和weak_ptr。

其中auto_ptr是C++98標準化引入的;
scope_ptr、shared_ptr和weak_ptr是C++11標準化才引入的(當然,早在C++03的TR1中就已經可以使用了)。我們都知道,auto_ptr雖說簡單,但使用起來卻到處是坑,以至于大家都不提倡使用。
shared_ptr是引用計數的智能指針,被奉為裸指針的完美替身,因此被廣泛使用。也可能正是這個原因,scope_ptr 和 weak_ptr似乎被大家遺忘了(或許還會以為它們純屬多余)。

上述言論引自網上
下面簡單總結下這幾個智能指針:

1.auto_ptr管理權轉移
帶有缺陷的設計 ----->c++98/03
在任何情況下都不要使用;

2.scoped_ptr(boost)
unique_ptr(c++11)
防拷貝--->簡單粗暴設計--->功能不全。

3、shared_ptr(boost/c++11)
引用計數--->功能強大(支持拷貝、支持定制刪除器)
缺陷---->循環引用(weak_ptr配合解決)。

這篇文章主要的內容是講解auto_ptr所引出的一系列問題:


一、auto_ptr智能指針

無論在什么情況下都不要使用,下面來詳細介紹下為什么不要使用它,可能會有人問,既然不讓使用,那么為什么還要把它放在c++的標準庫里呢?
是的,一開始我也是有這個疑問的,--->其實是因為c++標準庫里的內容一經規定,就不允許修改了)

下面模擬實現其基本功能:

1.AutoPtr的第一種實現方法:

采用資源轉移的方法。
一個指針將一塊空間的權限完全交給了另一個指針。(權限的轉移)



模擬實現代碼如下:

[cpp]?view plain?copy
  1. <span?style="font-size:18px;">template<class?T>??
  2. class?AutoPtr??
  3. {??
  4. public:??
  5. ????AutoPtr(T*?ptr?=?0)//構造函數??
  6. ????????:_ptr(ptr)??
  7. ????{??
  8. ????????ptr?=?NULL;??
  9. ????}??
  10. ??
  11. ????AutoPtr(AutoPtr<T>&?ap)//拷貝構造函數??
  12. ????????:_ptr(ap._ptr)??
  13. ????{??
  14. ????????ap._ptr?=?NULL;??
  15. ????}??
  16. ??
  17. ????AutoPtr<T>&?operator=(AutoPtr<T>&?ap)//賦值運算符重載??
  18. ????{??
  19. ????????if?(this?!=?&ap)??
  20. ????????{??
  21. ????????????if?(_ptr)??
  22. ????????????{??
  23. ????????????????delete?_ptr;??
  24. ????????????}??
  25. ????????????_ptr?=?ap._ptr;??
  26. ????????????ap._ptr?=?NULL;??
  27. ????????}??
  28. ????????return?*this;??
  29. ????}??
  30. ??
  31. ????~AutoPtr()//析構函數??
  32. ????{??
  33. ????????if?(_ptr)??
  34. ????????{??
  35. ????????????delete?_ptr;??
  36. ????????????_ptr?=?NULL;??
  37. ????????}??
  38. ????}??
  39. ??
  40. ????T&?operator*()??
  41. ????{??
  42. ????????return?*_ptr;??
  43. ????}??
  44. ??
  45. ????T*?operator->()??
  46. ????{??
  47. ????????return?_ptr;??
  48. ????}??
  49. private:??
  50. ????T*?_ptr;??
  51. };??
  52. ??
  53. void?Test1()??
  54. {??
  55. ????AutoPtr<int>?ap(new?int(1));??
  56. ????AutoPtr<int>?ap1(ap);??
  57. ????AutoPtr<int>?ap2;??
  58. ????ap2?=?ap1;??
  59. }</span>??



賦值運算符存在問題:
(由此可知對于動態內存空間只能由一個智能指針來管理,從而避免下面的問題。





存在的問題:
問題①:這種將一塊空間的權限完全交給別人的方法:

產生問題的是拷貝構造和賦值運算符重載函數。
當調用了拷貝構造或是賦值運算符的重載函數任意一個時:
假設調用了拷貝構造函數,我們的本意是用一個對象去構造一個與之一模一樣的對象,可是結果呢,我們把自己給弄丟了,完全沒有達到我們預期的目標。
所以當我們在上述代碼中的Test1中調用了拷貝構造函數時,如果我們想要修改第一次構造出來的對象的內容時,會發現對象的資源已經被清理了,所以會導致程序崩潰。

問題②:先看如下示例:

[cpp]?view plain?copy
  1. <span?style="font-size:18px;">#define?_CRT_SECURE_NO_WARNINGS?1??
  2. #include<iostream>??
  3. using?namespace?std;??
  4. ??
  5. template<class?T>??
  6. class?AutoPtr??
  7. {??
  8. public:??
  9. ????AutoPtr(T*?ptr?=?0)//構造函數??
  10. ????????:_ptr(ptr)??
  11. ????{??
  12. ????????ptr?=?NULL;??
  13. ????}??
  14. ??
  15. ????AutoPtr(AutoPtr<T>&?ap)//拷貝構造函數??
  16. ????????:_ptr(ap._ptr)??
  17. ????{??
  18. ????????ap._ptr?=?NULL;??
  19. ????}??
  20. ??
  21. ????AutoPtr<T>&?operator=(AutoPtr<T>&?ap)//賦值運算符重載??
  22. ????{??
  23. ????????if?(this?!=?&ap)??
  24. ????????{??
  25. ????????????if?(_ptr)??
  26. ????????????{??
  27. ????????????????delete?_ptr;??
  28. ????????????}??
  29. ????????????_ptr?=?ap._ptr;??
  30. ????????????ap._ptr?=?NULL;??
  31. ????????}??
  32. ????????return?*this;??
  33. ????}??
  34. ??
  35. ????~AutoPtr()//析構函數??
  36. ????{??
  37. ????????if?(_ptr)??
  38. ????????{??
  39. ????????????delete?_ptr;??
  40. ????????????_ptr?=?NULL;??
  41. ????????}??
  42. ????}??
  43. ??
  44. ????T&?operator*()??
  45. ????{??
  46. ????????return?*_ptr;??
  47. ????}??
  48. ??
  49. ????T*?operator->()??
  50. ????{??
  51. ????????return?_ptr;??
  52. ????}??
  53. private:??
  54. ????T*?_ptr;??
  55. };??
  56. ??
  57. AutoPtr<int>?Funtest()??
  58. {??
  59. ????AutoPtr<int>?ap(new?int(1));??
  60. ????return?ap;??
  61. }??
  62. ??
  63. void?Test1()??
  64. {??
  65. ????AutoPtr<int>?ap(new?int(1));??
  66. ????AutoPtr<int>?ap1(ap);??
  67. ????AutoPtr<int>?ap2;??
  68. ????ap2?=?ap1;??
  69. ???<span?style="color:#993399;">?</span><span?style="color:#006600;">AutoPtr<int>?ap4(Funtest());//返回值以值的形式返回,則為一個臨時對象,??
  70. ????//臨時對象具有常性,所以在拷貝構造ap4時,拷貝構造函數的參數應該由const修飾</span><span?style="color:#ff0000;">??
  71. ?????</span>??
  72. }??
  73. </span>??


問題③:

AutoPtr<int> ap(AutoPtr<int>(new int(1)))
//括號里是構造一個無名對象,無名對象,具有常性,和第②個問題一樣,在拷貝構造ap時,拷貝構造函數的參數應該由const來修飾,還有一個問題就是,在vs2010下,編譯器對其做了一些優化,本來這一條語句,應該是先調用構造函數構造匿名對象,然后由匿名對象去拷貝構造對象ap,但是由于在構造了匿名對象之后,又馬上去拷貝構造對象,而且是在一條語句執行的,所以編譯器對其進行了優化,只會調用構造函數,而不會去調用拷貝構造函數,將構造的無名對象值直接給了ap這個對象,所以在vs2010下程序并沒有崩潰,而在Linux下編譯時就會報出錯誤。

下面是我在Linux下測試時的代碼:



編譯錯誤:




總結:由上面的編譯錯誤我們可以得知,這種由一個常性對象去拷貝構造一個Auto_ptr的想法是不現實的,所以才有了第三種情況。

實際上,實現方法三就是為了解決用一個臨時右值對象去拷貝構造一個對象。


2.AutoPtr的第二種實現方法:

存在野指針的問題:
同樣用示例來分析這個問題:
[cpp]?view plain?copy
  1. <span?style="font-size:18px;">template<class?T>??
  2. class?AutoPtr??
  3. {??
  4. public:??
  5. ????AutoPtr(T*?ptr?=?0)//構造函數??
  6. ????????:_ptr(ptr)??
  7. ????????,?_owner(true)//當獨占資源時將其設置為true??
  8. ????{??
  9. ????????if?(!_ptr)??
  10. ????????{??
  11. ????????????_owner?=?false;??
  12. ????????}??
  13. ????}??
  14. ??
  15. ????AutoPtr(const?AutoPtr<T>&?ap)//拷貝構造函數??
  16. ????????:_ptr(ap._ptr)??
  17. ????????,?_owner(true)??
  18. ????{??
  19. ????????ap._owner?=?false;??
  20. ????}??
  21. ??
  22. ????AutoPtr&?operator=(const?AutoPtr<T>&?ap)//賦值運算符重載??
  23. ????{??
  24. ????????if?(this?!=?&ap)??
  25. ????????{??
  26. ????????????delete?_ptr;??
  27. ????????????_owner?=?true;??
  28. ????????????_ptr?=?ap._ptr;??
  29. ????????????ap._owner?=?false;??
  30. ????????}??
  31. ????????return?*this;??
  32. ????}??
  33. ??
  34. ????~AutoPtr()??
  35. ????{??
  36. ????????if?(_owner)??
  37. ????????{??
  38. ????????????delete?_ptr;??
  39. ????????????_ptr?=?NULL;??
  40. ????????????cout<<"~AutoPtr()"<<endl;??
  41. ????????}??
  42. ????}??
  43. ??
  44. ????T&?operator*()??
  45. ????{??
  46. ????????return?*_ptr;??
  47. ????}??
  48. ??
  49. ????T*?operator->()??
  50. ????{??
  51. ????????return?_ptr;??
  52. ????}??
  53. private:??
  54. ????T*?_ptr;??
  55. ????mutable?bool?_owner;//可被修改的??
  56. };??
  57. ??
  58. void?TestAutoPtr()??
  59. {??
  60. ????/*AutoPtr<int>?ap(new?int(10));?
  61. ????AutoPtr<int>?ap1(new?int(20));?
  62. ????AutoPtr<int>?ap2(ap1);?
  63. ????AutoPtr<int>?ap3;?
  64. ????ap3?=?ap;*/??
  65. ????AutoPtr<int>?ap4(AutoPtr<int>(new?int(20)));??
  66. ????if?(true)??
  67. ????{??
  68. ????????AutoPtr<int>?ap5(ap4);??
  69. ????}<span?style="color:#009900;">//作用域結束之后ap5已被析構,空間已被釋放</span>??
  70. ???<span?style="color:#ff0000;">?*ap4?=?10;//這時ap5與ap4共享一塊空間,既然ap5已被釋放,那么ap4對象維護的指針已成為野指針</span>??
  71. }??
  72. ??
  73. int?main()??
  74. {??
  75. ????TestAutoPtr();??
  76. ????return?0;??
  77. }</span>??

會發生內存泄漏,因為ap4與ap5共同管理一塊空間,當ap5出了if語句的作用域后,已被析構,空間被回收,那么在下面在去訪問ap4就有了問題,ap4已然成為了一個野指針。

③類型轉化

c++標準庫里的的auto_ptr的實現:
但還有是有缺陷:訪問空指針的問題無法規避,也就是實現方法一存在的第一個問題

我先貼出標準庫里的源碼:

[cpp]?view plain?copy
  1. <span?style="font-size:18px;">????????//?TEMPLATE?CLASS?auto_ptr??
  2. template<class?_Ty>??
  3. ????class?auto_ptr;??
  4. ??
  5. template<class?_Ty>??
  6. ????struct?auto_ptr_ref??
  7. ????????{???//?proxy?reference?for?auto_ptr?copying??
  8. ????explicit?auto_ptr_ref(_Ty?*_Right)<span?style="color:#009900;">//構造函數</span>??
  9. ????????:?_Ref(_Right)??
  10. ????????{???//?construct?from?generic?pointer?to?auto_ptr?ptr??
  11. ????????}??
  12. ??
  13. ????_Ty?*_Ref;??//?generic?pointer?to?auto_ptr?ptr??
  14. ????};??
  15. ??
  16. template<class?_Ty>??
  17. ????class?auto_ptr??
  18. ????????{???//?wrap?an?object?pointer?to?ensure?destruction??
  19. public:??
  20. ????typedef?auto_ptr<_Ty>?_Myt;??
  21. ????typedef?_Ty?element_type;??
  22. <span?style="color:#009900;">//一般的構造函數</span>??
  23. ????explicit?auto_ptr(_Ty?*_Ptr?=?0)?_THROW0()??
  24. ????????:?_Myptr(_Ptr)??
  25. ????????{???//?construct?from?object?pointer??
  26. ????????}??
  27. <span?style="color:#009900;">//一般的拷貝構造函數</span>??
  28. ????auto_ptr(_Myt&?_Right)?_THROW0()??
  29. ????????:?_Myptr(_Right.release())??
  30. ????????{???//?construct?by?assuming?pointer?from?_Right?auto_ptr??
  31. ????????}??
  32. <span?style="color:#009900;">//帶有隱式類型的構造函數</span>??
  33. ????auto_ptr(auto_ptr_ref<_Ty>?_Right)?_THROW0()??
  34. ????????{???//?construct?by?assuming?pointer?from?_Right?auto_ptr_ref??
  35. ????????_Ty?*_Ptr?=?_Right._Ref;??
  36. ????????_Right._Ref?=?0;????//?release?old??
  37. ????????_Myptr?=?_Ptr;??//?reset?this??
  38. ????????}??
  39. <span?style="color:#009900;">//類型轉換</span>??
  40. ????template<class?_Other>??
  41. ????????operator?auto_ptr<_Other>()?_THROW0()??
  42. ????????{???//?convert?to?compatible?auto_ptr??
  43. ????????return?(auto_ptr<_Other>(*this));??
  44. ????????}??
  45. <span?style="color:#009900;">//對象的類型轉換</span>??
  46. ????template<class?_Other>??
  47. ????????operator?auto_ptr_ref<_Other>()?_THROW0()??
  48. ????????{???//?convert?to?compatible?auto_ptr_ref??
  49. ????????_Other?*_Cvtptr?=?_Myptr;???//?test?implicit?conversion??
  50. ????????auto_ptr_ref<_Other>?_Ans(_Cvtptr);??
  51. ????????_Myptr?=?0;?//?pass?ownership?to?auto_ptr_ref??
  52. ????????return?(_Ans);??
  53. ????????}??
  54. <span?style="color:#009900;">//一般的賦值運算符重載函數</span>??
  55. ????template<class?_Other>??
  56. ????????_Myt&?operator=(auto_ptr<_Other>&?_Right)?_THROW0()??
  57. ????????{???//?assign?compatible?_Right?(assume?pointer)??
  58. ????????reset(_Right.release());??
  59. ????????return?(*this);??
  60. ????????}??
  61. ??
  62. /<span?style="color:#009900;">/拷貝構造函數?</span>??
  63. ????template<class?_Other>??
  64. ????????auto_ptr(auto_ptr<_Other>&?_Right)?_THROW0()??
  65. ????????:?_Myptr(_Right.release())??
  66. ????????{???//?construct?by?assuming?pointer?from?_Right??
  67. ????????}??
  68. <span?style="color:#009900;">//一般的構造函數</span>??
  69. ????_Myt&?operator=(_Myt&?_Right)?_THROW0()??
  70. ????????{???//?assign?compatible?_Right?(assume?pointer)??
  71. ????????reset(_Right.release());??
  72. ????????return?(*this);??
  73. ????????}??
  74. <span?style="color:#009900;">//帶有類型轉化的賦值運算符重載函數</span>??
  75. ????_Myt&?operator=(auto_ptr_ref<_Ty>?_Right)?_THROW0()??
  76. ????????{???//?assign?compatible?_Right._Ref?(assume?pointer)??
  77. ????????_Ty?*_Ptr?=?_Right._Ref;??
  78. ????????_Right._Ref?=?0;????//?release?old??
  79. ????????reset(_Ptr);????//?set?new??
  80. ????????return?(*this);??
  81. ????????}??
  82. <span?style="color:#009900;">//析構函數</span>??
  83. ????~auto_ptr()??
  84. ????????{???//?destroy?the?object??
  85. ????????delete?_Myptr;??
  86. ????????}??
  87. ??
  88. ????_Ty&?operator*()?const?_THROW0()??
  89. ????????{???//?return?designated?value??
  90. ?#if?_ITERATOR_DEBUG_LEVEL?==?2??
  91. ????????if?(_Myptr?==?0)??
  92. ????????????_DEBUG_ERROR("auto_ptr?not?dereferencable");??
  93. ?#endif?/*?_ITERATOR_DEBUG_LEVEL?==?2?*/??
  94. ??
  95. ????????return?(*get());??
  96. ????????}??
  97. ??
  98. ????_Ty?*operator->()?const?_THROW0()??
  99. ????????{???//?return?pointer?to?class?object??
  100. ?#if?_ITERATOR_DEBUG_LEVEL?==?2??
  101. ????????if?(_Myptr?==?0)??
  102. ????????????_DEBUG_ERROR("auto_ptr?not?dereferencable");??
  103. ?#endif?/*?_ITERATOR_DEBUG_LEVEL?==?2?*/??
  104. ??
  105. ????????return?(get());??
  106. ????????}??
  107. ??
  108. ????_Ty?*get()?const?_THROW0()??
  109. ????????{???//?return?wrapped?pointer??
  110. ????????return?(_Myptr);??
  111. ????????}??
  112. <span?style="color:#009900;">//為了轉交所有權</span>??
  113. ????_Ty?*release()?_THROW0()??
  114. ????????{???//?return?wrapped?pointer?and?give?up?ownership??
  115. ????????_Ty?*_Tmp?=?_Myptr;??
  116. ????????_Myptr?=?0;??
  117. ????????return?(_Tmp);??
  118. ????????}??
  119. <span?style="color:#009900;">//為了接收所有權</span>??
  120. ????void?reset(_Ty?*_Ptr?=?0)??
  121. ????????{???//?destroy?designated?object?and?store?new?pointer??
  122. ????????if?(_Ptr?!=?_Myptr)??
  123. ????????????delete?_Myptr;??
  124. ????????_Myptr?=?_Ptr;??
  125. ????????}??
  126. ??
  127. private:??
  128. ????_Ty?*_Myptr;????//?the?wrapped?object?pointer??
  129. ????};??
  130. </span>??


示例分析:

[cpp]?view plain?copy
  1. <span?style="font-size:18px;">#define?_CRT_SECURE_NO_WARNINGS?1??
  2. #include<iostream>??
  3. using?namespace?std;??
  4. #include<memory>??
  5. ??
  6. auto_ptr<int>?FunTest()??
  7. {??
  8. ????auto_ptr<int>?ap1(new?int(20));??
  9. ????return?ap1;//返回值為一個匿名對象??
  10. }??
  11. ??
  12. void?Test1()??
  13. {??
  14. ????auto_ptr<int>?ap1(new?int(10));//構造函數??
  15. ????auto_ptr<int>?ap2(new?int(20));//構造函數??
  16. ????auto_ptr<int>?ap3;??
  17. ????ap3?=?ap2;//賦值運算符重載??
  18. ????auto_ptr<int>?ap4(ap1);//拷貝構造??
  19. ????auto_ptr<int>?ap5(FunTest());//會發生類型轉化?,會先去調用這個類型轉化函數operator?auto_ptr_ref<_Other>(),</span>??
[cpp]?view plain?copy
  1. <span?style="font-size:18px;">//然后調用構造函數auto_ptr(auto_ptr_ref<_Ty>?_Right)。??
  2. }??
  3. </span>??

如果您還想知道標準庫里究竟是怎樣實現的,可以繼續往下看,希望可以對您有所幫助。



源碼分析:



























為了模擬一個一般指針,所以重載以下兩個符號是為了使得智能指針可以像一般指針一樣使用。



智能指針內封裝的一個原生態指針:





二、ScopedPtr(獨占空間--->防拷貝、防賦值)

其實在c++標準庫里稱為unique_ptr,很好理解了,因為AutoPtr就是因為轉移資源,以及轉交權限從而引發一系列的問題的,追根到底其實就是拷貝構造和賦值運算符重載函數導致的。所以這個智能指針就是防拷貝和賦值的)。

因為AutoPtr智能指針在拷貝構造和賦值運算符重載方面有些許問題,所以就有了ScopedPtr,既然拷貝構造和賦值運算符重載會引發一些問題,那么是不是可以不允許它拷貝和賦值呢?

既然拷貝和賦值容易出現問題,那么這種智能指針就不允許拷貝和賦值。
解決上述問題的方法:

實現這種機制的方法有三種:
1)將拷貝構造函數和賦值運算符重載函數的聲明寫成公有的,但是對這兩個函數不進行定義。
2)將拷貝構造函數和賦值運算符重載函數在類型直接實現,但是將它們的訪問限定符設定為私有的。
3)將拷貝構造函數和賦值運算符重載函數的聲明寫成私有的,但是對這兩個函數不進行定義。

分析上述三種方法:
第一種:如果將其聲明為公有的,那么如果有其他人在類外對你的拷貝構造和賦值運算符重載函數進行實現,那么還是沒有達到防拷貝、防賦值的要求。--->pass掉
第二種:個人覺得,既然都已經不允許拷貝和賦值了,為什么還要多此一舉的寫出其實現方法呢?所以呢----->pass掉
所以:就第三種方法覺得合適。

在這里我只貼出第三種方法的代碼:


[cpp]?view plain?copy
  1. <span?style="font-size:18px;">//防拷貝、防賦值??
  2. template<class?T>??
  3. class?ScopedPtr??
  4. {??
  5. public?:??
  6. ????ScopedPtr(T*?ptr)//構造函數??
  7. ????????:_ptr(ptr)??
  8. ????{}??
  9. ????~ScopedPtr()//析構函數??
  10. ????{??
  11. ????????if?(NULL?!=?_ptr)??
  12. ????????{??
  13. ????????????delete?_ptr;??
  14. ????????????_ptr?=?NULL;??
  15. ????????}??
  16. ????}??
  17. ??
  18. ????T&?operator*()??
  19. ????{??
  20. ????????return?*_ptr;??
  21. ????}??
  22. ??
  23. ????T*?operator->()??
  24. ????{??
  25. ????????return?_ptr;??
  26. ????}??
  27. private?:??
  28. ????ScopedPtr(const?ScopedPtr&?ap);//拷貝構造函數聲明??
  29. ????ScopedPtr&?operator=(const?ScopedPtr&?ap);//賦值運算符重載函數聲明??
  30. ????T*?_ptr;??
  31. };??
  32. ??
  33. void?Test1()??
  34. {??
  35. ????ScopedPtr<int>?sp1(new?int(10));??
  36. ????*sp1?=?20;??
  37. }</span>??

scoped_array//管理數組
boost庫里面的,c++標準庫由于已經有相似功能的vector,所以并未將其此加入)
[cpp]?view plain?copy
  1. <span?style="font-size:18px;">//管理數組(防拷貝、防賦值)??
  2. template<class?T>??
  3. class?ScopedArray??
  4. {??
  5. public:??
  6. ????ScopedArray(T*?ptr?=?0)//構造函數??
  7. ????????:_ptr(ptr)??
  8. ????{}??
  9. ????~ScopedArray()//析構函數??
  10. ????{??
  11. ????????if?(NULL?!=?_ptr)??
  12. ????????{??
  13. ????????????delete[]?_ptr;??
  14. ????????????_ptr?=?NULL;??
  15. ????????}??
  16. ????}??
  17. //基本操作??
  18. ????T&?operator*()??
  19. ????{??
  20. ????????return?*_ptr;??
  21. ????}??
  22. //基本操作??
  23. ????T*?operator->()??
  24. ????{??
  25. ????????return?_ptr;??
  26. ????}??
  27. //基本操作??
  28. ????T&?operator[](size_t?index)??
  29. ????{??
  30. ????????return?_ptr[index];??
  31. ????}??
  32. private:??
  33. ????ScopedArray(const?ScopedArray<T>&?ap);??
  34. ????ScopedArray&?operator=(const?ScopedArray<T>&?ap);??
  35. ????T*?_ptr;??
  36. };</span>??

總結:c++標準庫里的智能指針只能管理單個對象的動態空間,而不能讓其管理一段連續空間,例如:動態開辟的數組的空間。

auto_ptr無論什么時候都不要使用
scoped_ptr是對auto_ptr所存在的問題的一個解決。
所以一般面試時,沒有特別指定讓你實現哪個智能指針,最好寫出這個,因為這個最簡單呀,千萬不要寫出auto_ptr,這個智能指針存在缺陷!

雖然c++標準庫里面加入了auto_ptr智能指針,但是還是不要使用它,c++標準庫里仍然保留它,應該是為了向前兼容。
因為既然已經加入了標準庫,那么肯定會有程序員使用的,所以還是不能隨意廢棄掉。

后續我還會繼續總結關于shared_ptr的實現細節。



題外話:

因為剛開始接觸智能指針,自身能力不足,所以哪里寫的有問題的歡迎大家提出來。
共同進步!
每天進步一點點!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385028.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385028.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385028.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

隨機數

隨機數產生器rand(),頭文件為#include<stdlib.h> #include<stdio.h> #include<stdlib.h>int main() {int value;int i;for(i 0; i < 10; i){value rand();printf("value %d\n",value);}return 0; } 運行結果&#xff1a; value 41 value 1…

多重繼承之虛繼承(主要是為了解決產生的數據冗余問題)

虛繼承 是面向對象編程中的一種技術&#xff0c;是指一個指定的基類&#xff0c;在繼承體系結構中&#xff0c;將其成員數據實例共享給也從這個基類型直接或間接派生的其它類。形式&#xff1a;在繼承定義中包含了virtual關鍵字的繼承關系&#xff0c;如下圖中&#xff0c;類A就…

通過syslog接收遠程日志

通過syslog接收遠程日志通過syslog接收遠程主機的日志&#xff0c;需要做一些環境配置。客戶機A通過syslog將日志信息發送到服務主機B&#xff08;或稱日志采集服務器&#xff09;。以下說明配置過程&#xff08;我的實驗環境是&#xff0c;客戶機A&#xff1a;Solaris 10&…

linux syslog服務器配置,自動發日志到另一臺日志服務器

1.客戶端:168.1.20.66修改/etc/syslog.conf 添加syslog.info 168.1.80.302.日志服務器:168.1.80.30修改/etc/sysconf/syslog 修改SYSLOGD_OPTIONS為 "-r -x -m 0" #-r表示允許接收外來的消息&#xff0c;-x表示不解析DNS, #-m 0表示時間戳標記間隔,如果指定只接…

Make文件(一)

基本規則&#xff1a; 目標&#xff1a;依賴 &#xff08;tab&#xff09;規則 目標&#xff1a;需要生成的目標文件 依賴&#xff1a;生成該目標所需的一些文件 規則&#xff1a;由依賴文件生成目標文件的手段 tab&#xff1a;每條規則前必須以tab開頭&#xff0c;使用空格不行…

移植驅動完畢后加載時的version magic報錯原因以及解決辦法

History:2012-02-17Author:yingru移植rt3070的AP驅動到裝有fedora14的PC機上時&#xff0c;模塊編譯完畢后&#xff0c;加載時提示invalid module format。PC機環境介紹&#xff1a;內核版本&#xff1a;2.6.35.6-45.fc14.i686命令行輸入dmesg查看最后的日志&#xff0c;發現如…

/proc 虛擬文件系統(實例)

Linux下有一個神奇的目錄/proc&#xff0c;經常會運行 cat /proc/cpuinfo 命令查看cpu信息&#xff0c;/proc下的確有cpuinfo文件&#xff0c;但是這個文件不是物理存在的&#xff0c;是軟件虛擬出來的&#xff0c;與普通文件不同&#xff0c;該文件是動態的。通過/proc可以實現…

內核模塊中對文件的讀寫

平時網絡部分的東西碰的多些&#xff0c;這塊一開始還真不知道怎么寫&#xff0c;因為肯定和在用戶空間下是不同的。google過后&#xff0c;得到以下答案。一般可以用兩種方法&#xff1a;第一種是用系統調用。第二種方法是filp->open()等函數。下面分別來說下這兩種方法。1…

Makefile文件試錯

1成功&#xff1a; src $(wildcard ./*cpp) obj $(patsubst %.cpp,%.o ,$(src))target test$(target) : $(obj)g $(obj) -o $(target) -I/usr/include/mysql -L/usr/lib/mysql/ -lmysqlclient %.o: %.cppg -c $< -o $ -I/usr/include/mysql -L/usr/lib/mysql/ -lmysql…

內核定時器timer_list使用

Linux內核中提供了timer使用的API&#xff0c;做一個簡單的記要。 1. 包含的頭文件&#xff1a;linux/timer.h 2. 數據類型&#xff1a;struct timer_list; 包含的主要成員&#xff1a; a. data:傳遞到超時處理函數的參數&#xff0c;主要在多個定時器同時使用時&#xff0c;區…

內存四區

1.代碼區&#xff1a; 代碼區Code&#xff0c;程序被操作系統加載到內存的時候&#xff0c;所有的可執行代碼都加載到代碼區&#xff0c;也叫代碼段&#xff0c;這塊內存是不可以在運行期間修改的。 2. 靜態區 所有的全局變量以及程序中的靜態變量都存儲在靜態區。 #include<…

最高效的進(線)程間通信機制--eventfd

我們常用的進程&#xff08;線程&#xff09;間通信機制有管道&#xff0c;信號&#xff0c;消息隊列&#xff0c;信號量&#xff0c;共享內存&#xff0c;socket等等&#xff0c;其中主要作為進程&#xff08;線程&#xff09;間通知/等待的有管道pipe和socketpair。線程還有特…

malloc,calloc,realloc

與堆操作相關的兩個函數 malloc #include<stdio.h> #include<stdlib.h> #include<string.h>int main() {char *p malloc(10); //內存隨機&#xff0c;未做處理int i;for(i 0; i < 10: i){printf(“%d “,p[i]);} free(p);return 0; } 運行結果&…

Linux內核同步機制之completion

內核編程中常見的一種模式是&#xff0c;在當前線程之外初始化某個活動&#xff0c;然后等待該活動的結束。這個活動可能是&#xff0c;創建一個新的內核線程或者新的用戶空間進程、對一個已有進程的某個請求&#xff0c;或者某種類型的硬件動作&#xff0c;等等。在這種情況下…

可變參數函數(一)

一個函數可以接受不定數的參數個數&#xff0c;這就是可變參數函數&#xff0c;比較常見的比如printf(),scanf()&#xff1b; printf(const char* format,…); printf(“%d”,i); printf(“%s”,s); printf(“the number is %d,stirng is :%s”,i,s); 變量參數函數的簡單實現&a…

Linux內核線程kernel thread詳解--Linux進程的管理與調度

內核線程為什么需要內核線程Linux內核可以看作一個服務進程(管理軟硬件資源&#xff0c;響應用戶進程的種種合理以及不合理的請求)。 內核需要多個執行流并行&#xff0c;為了防止可能的阻塞&#xff0c;支持多線程是必要的。 內核線程就是內核的分身&#xff0c;一個分身可以處…

可變參數函數(二)

函數樣例&#xff1a; #include<stdio.h> #include<stdlib.h> #include<stdarg.h>double add(int n,...) {int i 0;double sum 0;va_list argptr;va_start(argptr,n);for(i 0 ; i < n; i){double d va_arg(argptr,double);printf("%d argument …

Linux 內核網絡協議棧 ------sk_buff 結構體 以及 完全解釋 (2.6.16)

在2.6.24之后這個結構體有了較大的變化&#xff0c;此處先說一說2.6.16版本的sk_buff&#xff0c;以及解釋一些問題。一、先直觀的看一下這個結構體~~~~~~~~~~~~~~~~~~~~~~在下面解釋每個字段的意義~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可變參數輸出(三)

Linux C關于輸出函數的定義&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的設計模式---適配器模式(C++實現)

適配器模式屬于結構型的設計模式&#xff0c;它是結構型設計模式之首&#xff08;用的最多的結構型設計模式&#xff09;。 適配器設計模式也并不復雜&#xff0c;適配器它是主要作用是將一個類的接口轉換成客戶希望的另外一個接口這樣使得原本由于接口不兼容而不能一起工作的那…