C++智能指针简单实现

女爷i 2022-06-10 03:06 305阅读 0赞
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <list>
  5. namespace smart_pointer {
  6. // RAII(Resource Acquisition Is Initialization):资源分配即初始化,是管理资源、避免内存泄露的方法。
  7. // 方法是:定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的的清理,可以保证资源的正确初始化和释放。
  8. // 参考 http://blog.csdn.net/ER_Plough/article/details/48206439?ref=myread
  9. // http://blog.csdn.net/daniel_ustc/article/details/23096229
  10. // 循环引用
  11. // 循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用。
  12. // 即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是在B析构后才析构A,这就是循环引用问题,违反常规,导致内存泄露。
  13. // 解决循环引用方法:
  14. // 1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
  15. // 2. 当A的生存期超过B的生存期的时候,B改为使用一个普通指针指向A。
  16. // 3. 使用weak_ptr打破这种循环引用,因为weak_ptr不会修改计数器的大小,所以就不会产生两个对象互相使用一个shared_ptr成员变量指向对方的问题,从而不会引起引用循环。
  17. // 强引用和弱引用
  18. // 一个强引用当被引用的对象活着的话,这个引用也存在(就是说,当至少有一个强引用,那么这个对象就不能被释放)。
  19. // share_ptr就是强引用。相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它存在的时候的一个引用。弱引用并不修改该对象的引用计数,
  20. // 这意味这弱引用它并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。
  21. // 1.AutoPtr-----管理权转移
  22. // 2.ScopedPtr------防拷贝
  23. // 3.SharePtr------引用计数
  24. //-----------------------------------------------------------------------------------
  25. // 1.AutoPtr
  26. template<class T>
  27. class AutoPtr {
  28. public:
  29. explicit AutoPtr(T* ptr);
  30. ~AutoPtr();
  31. AutoPtr(AutoPtr<T>& auto_ptr);
  32. T* get() const {
  33. return ptr_;
  34. }
  35. void reset(T* ptr);
  36. T& operator*() const {
  37. return *ptr_;
  38. }
  39. T* operator->() const {
  40. return ptr_;
  41. }
  42. bool operator!() const {
  43. return ptr_ == NULL;
  44. }
  45. explicit operator bool() const {
  46. return ptr_ != NULL;
  47. }
  48. AutoPtr& operator=(AutoPtr<T>& auto_ptr);
  49. private:
  50. T* ptr_;
  51. };
  52. template<class T>
  53. AutoPtr<T>::AutoPtr(T* ptr)
  54. : ptr_(ptr) {
  55. }
  56. template<class T>
  57. AutoPtr<T>::~AutoPtr() {
  58. if (ptr_ != NULL) {
  59. delete ptr_;
  60. ptr_ = NULL;
  61. }
  62. }
  63. template<class T>
  64. AutoPtr<T>::AutoPtr(AutoPtr<T>& auto_ptr) {
  65. ptr_ = auto_ptr.ptr_;
  66. auto_ptr.ptr_ = NULL;
  67. }
  68. template<class T>
  69. AutoPtr<T>& AutoPtr<T>::operator=(AutoPtr<T>& auto_ptr) {
  70. if (&auto_ptr == this) {
  71. return *this;
  72. }
  73. if (ptr_ != NULL) {
  74. delete ptr_;
  75. }
  76. ptr_ = auto_ptr.ptr_;
  77. auto_ptr.ptr_ = NULL;
  78. return *this;
  79. }
  80. template<class T>
  81. void AutoPtr<T>::reset(T* ptr) {
  82. if (ptr_ != NULL) {
  83. delete ptr_;
  84. }
  85. ptr_ = ptr;
  86. }
  87. template<class T, class D>
  88. bool operator==(const AutoPtr<T>& lhs, const AutoPtr<D>& rhs) {
  89. return lhs.get() == rhs.get();
  90. }
  91. template<class T, class D>
  92. bool operator!=(const AutoPtr<T>& lhs, const AutoPtr<D>& rhs) {
  93. return lhs.get() != rhs.get();
  94. }
  95. //-----------------------------------------------------------------------------------
  96. // ScopedPtr
  97. template<class T>
  98. class ScopedPtr {
  99. public:
  100. explicit ScopedPtr(T* ptr)
  101. : ptr_(ptr) {
  102. }
  103. ~ScopedPtr() {
  104. if (ptr_ != NULL) {
  105. delete ptr_;
  106. ptr_ = NULL;
  107. }
  108. }
  109. T* operator->() const {
  110. return ptr_;
  111. }
  112. private:
  113. ScopedPtr(const ScopedPtr<T>& scoped_ptr);
  114. ScopedPtr& operator=(const ScopedPtr<T>& scoped_ptr);
  115. private:
  116. T* ptr_;
  117. };
  118. //-----------------------------------------------------------------------------------
  119. // ScopedPtr
  120. template<class T>
  121. class SharedPtr {
  122. public:
  123. explicit SharedPtr(T* ptr)
  124. : ptr_(ptr) {
  125. count_ = new int(1);
  126. }
  127. SharedPtr()
  128. : ptr_(NULL)
  129. , count_(NULL) {
  130. }
  131. ~SharedPtr() {
  132. Release();
  133. }
  134. SharedPtr(const SharedPtr<T>& shared_ptr)
  135. : ptr_(shared_ptr.ptr_)
  136. , count_(shared_ptr.count_) {
  137. ++(*count_);
  138. }
  139. SharedPtr<T>& operator=(const SharedPtr<T>& shared_ptr) {
  140. if (&shared_ptr != this) {
  141. Release();
  142. ptr_ = shared_ptr.ptr_;
  143. count_ = shared_ptr.count_;
  144. ++(*count_);
  145. }
  146. return *this;
  147. }
  148. T* operator->() const {
  149. return ptr_;
  150. }
  151. private:
  152. void Release() {
  153. if (ptr_ == NULL) {
  154. return;
  155. }
  156. --(*count_);
  157. if (*count_ == 0) {
  158. delete ptr_;
  159. delete count_;
  160. }
  161. }
  162. private:
  163. T* ptr_;
  164. int* count_;
  165. };
  166. //-----------------------------------------------------------------------------------
  167. // Test
  168. class String1 {
  169. public:
  170. explicit String1(const std::string& name)
  171. : name_(name) {
  172. std::cout << "Construct String1 : " << name_ << "!" << std::endl;
  173. }
  174. ~String1() {
  175. std::cout << "Destruct String1! : " << name_ << "!" << std::endl;
  176. }
  177. void Print() {
  178. std::cout << "I am " << name_ << "!" << std::endl;
  179. }
  180. private:
  181. std::string name_;
  182. };
  183. class B;
  184. class A {
  185. public:
  186. SharedPtr<B> b;
  187. ~A() {
  188. std::cout << "Destruct A!" << std::endl;
  189. }
  190. };
  191. class B {
  192. public:
  193. SharedPtr<A> a;
  194. ~B() {
  195. std::cout << "Destruct B!" << std::endl;
  196. }
  197. };
  198. static void TestAutoPtr() {
  199. AutoPtr<String1> ptr1(new String1("N1"));
  200. AutoPtr<String1> ptr2(ptr1);
  201. if (ptr1.get() == NULL) {
  202. std::cout << "true" << std::endl;
  203. }
  204. AutoPtr<String1> ptr3(new String1("N2"));
  205. ptr3 = ptr2;
  206. if (ptr2.get() == NULL) {
  207. std::cout << "true" << std::endl;
  208. }
  209. ptr3.reset(new String1("N4"));
  210. (*ptr3).Print();
  211. ptr3->Print();
  212. AutoPtr<int> ptr4(NULL);
  213. if (!ptr4) {
  214. std::cout << "true" << std::endl;
  215. }
  216. if (ptr3) {
  217. std::cout << "true" << std::endl;
  218. }
  219. if (ptr3 == ptr1) {
  220. std::cout << "true" << std::endl;
  221. }
  222. if (ptr3 != ptr1) {
  223. std::cout << "true" << std::endl;
  224. }
  225. }
  226. static void TestScopedPtr() {
  227. ScopedPtr<String1> ptr1(new String1("M1"));
  228. //ScopedPtr<String1> ptr2(ptr1); // error
  229. ScopedPtr<String1> ptr3(new String1("M3"));
  230. //ptr3 = ptr1; // error
  231. ptr1->Print();
  232. }
  233. static void TestSharedPtr() {
  234. SharedPtr<String1> ptr1(new String1("Z1"));
  235. SharedPtr<String1> ptr2(new String1("Z2"));
  236. SharedPtr<String1> ptr3(ptr1);
  237. ptr2 = ptr3;
  238. ptr1->Print();
  239. ptr2->Print();
  240. ptr3->Print();
  241. }
  242. static void TestCircularReference() {
  243. SharedPtr<A> a(new A);
  244. SharedPtr<B> b(new B);
  245. a->b = b;
  246. b->a = a;
  247. }
  248. static void TestDestructOrder() {
  249. String1 a("a");
  250. String1 b("b");
  251. }
  252. } // smart_pointer
  253. int main_smart() {
  254. using namespace smart_pointer;
  255. //TestDestructOrder();
  256. //TestAutoPtr();
  257. //TestScopedPtr();
  258. //TestSharedPtr();
  259. //TestCircularReference();
  260. return 0;
  261. }

发表评论

表情:
评论列表 (有 0 条评论,305人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++智能指针简单剖析

    智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。 1. 智能指针背后的设

    相关 基于C++实现一个简单智能指针

    在C、C++类的语言当中对指针的使用是十分常见和重要的,但是使用指针也很容易导致内存泄漏、不安全的情况发生,本文就针对这种情况来实现一个简单的智能指针类,通过这个类实现对指针操

    相关 C++-智能指针——简单实现分析

    > 一:为什么要有智能指针 在我们动态开辟内存时,每次new完就一定会有配套的delete来完成释放操作。可是这时候问题就来了,有时候程序未必会执行到我们释放的那一步,