c++ [wrong]simple "Garbage Collector"

In fact, Ptr alone can accomplish the task mentioned below.

Implementation see Ptr.h, main2.cpp. In C++11, we also have a better choice: std::shared_ptr (as you can see in main3.cpp).

main2.cpp

 1 #include "Ptr.h"

 2 

 3 #include <iostream>

 4 

 5 using namespace std;

 6 

 7 class Box

 8 {

 9     public:

10         void dosomething() { cout << "Box dosomething" << endl; }

11         Box() { cout << "Box cons" << endl; }

12         ~Box() { cout << "Box des" << endl; }

13 };

14 

15 Ptr<Box> global;

16 

17 

18 Ptr<Box> func() {

19     Ptr<Box> pb(new Box());

20     return pb;

21 }

22 

23 void call(Ptr<Box> ptr)

24 {

25     if(ptr)

26         ptr->dosomething();

27     else

28         cout << "ptr is null" << endl;

29 }

30 

31 

32 

33 int main()

34 {

35     Ptr<Box> p = func();

36     p->dosomething();

37     (*p).dosomething();

38     Ptr<Box> p2 = p;

39     call(p2);

40     p2.reset();

41     cout << "after p2.reset" << endl;

42     global = p;

43     p.reset();

44     call(p);

45     (*global).dosomething();

46     global.reset();

47     cout << "after global.reset" << endl;

48     return 0;

49 }

 

Ptr.h

 1 #ifndef PTR_H

 2 #define PTR_H

 3 

 4 #include <cstddef>

 5 

 6 template <typename TYPE>

 7 class Ptr {

 8 

 9     public:

10         void reset()

11         {

12             dec_use();

13         }

14         Ptr& operator=(const Ptr<TYPE> &copy)

15         {

16             dec_use();

17             obj = copy.obj;

18             use_count = copy.use_count;

19             if (use_count) ++*use_count;

20             return *this;

21         }

22         TYPE* operator->() { return obj; }

23         TYPE& operator*() { return *obj; }

24         const TYPE* operator->() const { return obj; }

25         const TYPE& operator*() const { return *obj; }

26         operator bool() const { return (obj != NULL); }

27 

28         Ptr(): obj(NULL), use_count(NULL) {}

29         Ptr(TYPE *obj_): obj(obj_), use_count(new int(1)) {}

30         Ptr(const Ptr &copy): obj(NULL), use_count(NULL)

31         {

32             obj = copy.obj;

33             use_count = copy.use_count;

34             if (use_count) ++*use_count;

35         }

36         ~Ptr()

37         {

38             dec_use();

39         }

40     private:

41         void dec_use() // decrease use_count

42         {

43             if (use_count != NULL) {

44                 if( --*use_count == 0) {

45                     delete obj;

46                     delete use_count;

47                 }

48                 obj = NULL;

49                 use_count = NULL;

50             }

51         }

52         TYPE *obj; // the actual object

53         int *use_count; // number of Ptr objects point to 'obj'

54 };

55 

56 #endif // PTR_H

 

main3.cpp

 1 #include <memory>

 2 

 3 #include <iostream>

 4 

 5 using namespace std;

 6 

 7 class Box

 8 {

 9     public:

10         void dosomething() { cout << "Box dosomething" << endl; }

11         Box() { cout << "Box cons" << endl; }

12         ~Box() { cout << "Box des" << endl; }

13 };

14 

15 shared_ptr<Box> global;

16 

17 

18 shared_ptr<Box> func() {

19     shared_ptr<Box> pb(new Box());

20     return pb;

21 }

22 

23 void call(shared_ptr<Box> ptr)

24 {

25     if(ptr)

26         ptr->dosomething();

27     else

28         cout << "ptr is null" << endl;

29 }

30 

31 

32 

33 int main()

34 {

35     shared_ptr<Box> p = func();

36     p->dosomething();

37     (*p).dosomething();

38     shared_ptr<Box> p2 = p;

39     call(p2);

40     p2.reset();

41     cout << "after p2.reset" << endl;

42     global = p;

43     p.reset();

44     call(p);

45     (*global).dosomething();

46     global.reset();

47     cout << "after global.reset" << endl;

48     return 0;

49 }

 

---------------------------------------- stupidest iead I've ever seen -----------------------------------------

|                                                                                                                                                         |

|                                                                                                                                                         |

The idea is to create a Ptr type that acts like a reference in Java.

And A Garbage Collector (MemMgr) type that acts like a garbage collector in Java.

Just a toy. :D

Question: why not delete all memory fragments managed by MemMgr in its destructor?

Answer: If you want to delete a piece of memory, you must cast the void* pointer to the exact type of that memory. However, there's no way for a MemMgr to know the type of the memory pieces, because type information is not managed by MemMgr. And you can't use the free function from <cstdlib>. For example, if you write "MemMgr *p = new MemMgr; free(p);" you'll find that the destructor of MemMgr is not called. And As shown in "test.cpp". "free" only works in pair with "malloc" or "realloc" etc functions in <cstdlib>. "delete" should work in pair with "new". 

 

see this question: http://stackoverflow.com/questions/1518711/how-does-free-know-how-much-to-free

 

test.cpp

1 #include "MemMgr.h"

2 #include <cstdlib>

3 

4 int main()

5 {

6     MemMgr *p = new MemMgr;

7     free(p);

8     return 0;

9 }

 

main.cpp

 1 #include "MemMgr.h"

 2 

 3 #include <iostream>

 4 

 5 using namespace std;

 6 

 7 class Box

 8 {

 9     public:

10         void dosomething() { cout << "Box dosomething" << endl; }

11         Box() { cout << "Box cons" << endl; }

12         ~Box() { cout << "Box des" << endl; }

13 };

14 

15 Ptr<Box> global;

16 MemMgr mgr;

17 

18 

19 Ptr<Box> func() {

20     Ptr<Box> pb = mgr.regist(new Box());

21     return pb;

22 }

23 

24 

25 

26 int main()

27 {

28     Ptr<Box> p = func();

29     p->dosomething();

30     (*p).dosomething();

31     Ptr<Box> p2 = p;

32     p2->dosomething();

33     cout << "end of main" << endl;

34     global = p2;

35     return 0;

36 }

 

MemMgr.h

  1 #ifndef MEMMGR_H

  2 #define MEMMGR_H

  3 

  4 #include <map>

  5 

  6 template <typename TYPE>

  7 class Ptr;

  8 

  9 /**

 10     MemMgr take the idea of Garbage Collector

 11     from the Java language. It's just much simple

 12     and limited.

 13 */

 14 class MemMgr

 15 {

 16     template <typename T> friend class Ptr;

 17     private:

 18         typedef unsigned long count;

 19         template <typename T> void login(T* ptr_obj);

 20         template <typename T> void logout(T* ptr_obj);

 21         std::map<void*, count> cmap;

 22     public:

 23         MemMgr();

 24         /**

 25             Client is responsible to ensure obj is in the heap,

 26             and make sure only use Ptr objects rather than ordinary

 27             pointers when manipulating objects managed by MemMgr.

 28 

 29             Otherwise the behavior of the MemMgr is undefined.

 30 

 31             If MemMgr is destroyed before any Ptr object managed

 32             by it, all Ptr objects managed by that MemMgr are corrupted

 33             and their behavior is undefined, which eventually leads to

 34             memory leak.

 35 

 36             So it's crucial to make sure MemMgr is not destroyed

 37             before ALL Ptr objects managed by it are destroyed.

 38         */

 39         template <typename T> Ptr<T> regist(T *obj);

 40         ~MemMgr();

 41 

 42 };

 43 

 44 /**

 45     Ptr acts like a reference in java.

 46 */

 47 template <typename TYPE>

 48 class Ptr {

 49 

 50     friend class MemMgr;

 51 

 52     public:

 53         Ptr& operator=(const Ptr<TYPE> &copy)

 54         {

 55             if(copy) {

 56                 logout();

 57                 obj = copy.obj;

 58                 mgr = copy.mgr;

 59                 copy.mgr->login(&obj);

 60             } // else leaves obj and mgr NULL

 61             return *this;

 62         }

 63         TYPE* operator->() { return obj; }

 64         TYPE& operator*() { return *obj; }

 65         const TYPE* operator->() const { return obj; }

 66         const TYPE& operator*() const { return *obj; }

 67         operator bool() const { return ( (obj != NULL) && (mgr != NULL) ); }

 68 

 69         Ptr(): obj(NULL), mgr(NULL) {}

 70         Ptr(const Ptr &copy): obj(NULL), mgr(NULL)

 71         {

 72             if(copy) {

 73                 obj = copy.obj;

 74                 mgr = copy.mgr;

 75                 copy.mgr->login(obj);

 76             }

 77         }

 78         ~Ptr()

 79         {

 80             logout();

 81         }

 82     private:

 83         Ptr(TYPE *_obj, MemMgr *_mgr): obj(_obj), mgr(_mgr)

 84         {

 85             mgr->login(obj);

 86         }

 87         void logout() {

 88             if (*this) {

 89                 mgr->logout(obj); obj = NULL; mgr = NULL;

 90             }

 91         }

 92         TYPE *obj;

 93         MemMgr *mgr;

 94 };

 95 

 96 

 97 template <typename T> Ptr<T> MemMgr::regist(T *obj)

 98 {

 99     return Ptr<T>(obj, this);

100 }

101 

102 template <typename T>

103 void MemMgr::login(T* ptr_obj)

104 {

105     std::map<void*, count>::iterator iter = cmap.find(ptr_obj);

106     if (iter != cmap.end()) {

107         ++(iter->second);

108     } else {

109         cmap.insert(std::pair<void*, count>(ptr_obj, 1));

110     }

111 }

112 

113 template <typename T>

114 void MemMgr::logout(T* ptr_obj)

115 {

116     std::map<void*, count>::iterator iter = cmap.find(ptr_obj);

117     if (iter != cmap.end()) {

118         --(iter->second);

119         if (iter->second == 0) {

120             T *p = (T*)(iter->first);

121             delete p;

122         }

123     }

124 }

125 

126 #endif // MEMMGR_H

 

 

MemMgr.cpp

 1 #include "MemMgr.h"

 2 

 3 #include <iostream>

 4 

 5 using namespace std;

 6 

 7 MemMgr::MemMgr()

 8 {

 9     cout << "MemMgr cons" << endl;

10 }

11 

12 MemMgr::~MemMgr()

13 {

14     cout << "MemMgr des" << endl;

15 }

 

你可能感兴趣的:(c++ [wrong]simple "Garbage Collector")