4.2 Detachment

One source of problem with pointers is what should happen when the value of a pointer changes. As a pointer stops pointing to whatever it was pointing at, will the action cause memory leak?

One reason why this is a common problem is that we use the assignment operator to alter what a pointer points to without thinking about the consequences. This is actually why operator overloading can be confusing. The same operator may be harmless in some situations, where very harmful in others.

Even our WhereIs class has this problem. When we make a WhereIs an alias of another WhereIs, what happens to whatever it was pointing at first? To make the programmer aware of such problems, we change the definition of WhereIs as in listing 2.


Listing 2:WhereIs.02
 
1class CheckMemLeak 
2{ 
3}; 
4 
5class PayLoadType 
6{ 
7    int x; 
8  public: 
9    void setx(int v) { x = v; } 
10    int getx(void) { return x; } 
11}; 
12 
13 
14template <class T> 
15class WhereIs 
16{ 
17  // private section of WhereIs 
18    class ThisIsA 
19    { 
20      // private section of ThisIsA 
21        T payload; 
22      public: 
23        T &getPayload(void) { return payload; } 
24        ThisIsA(const T &original):payload(original) {} 
25        ThisIsA(void) {} 
26    }; 
27    ThisIsA *ptr; 
28  public: 
29    WhereIs(void):ptr(0) {} 
30    WhereIs(WhereIs<T> &other):ptr(other.ptr) {} 
31    ~WhereIs(void) 
32    { 
33      if (ptr) throw CheckMemLeak(); 
34    } 
35    T & operator*(void) { return ptr->getPayload(); } 
36    void nuke(void) { delete ptr; ptr = 0; } 
37    void allocate(void) 
38    { 
39      if (ptr) throw CheckMemLeak(); 
40      ptr = new ThisIsA; 
41    } 
42    void allocate(const T &original) 
43    { 
44      if (ptr) throw CheckMemLeak(); 
45      ptr = new ThisIsA(original); 
46    } 
47    void becomesAliasOf(WhereIs<T> &other) 
48    { 
49      if (ptr) throw CheckMemLeak(); 
50      ptr = other.ptr; 
51    } 
52    void detach(void) { ptr = 0; } 
53}; 
54 
55void test(void) 
56{ 
57  WhereIs<PayLoadType> v,w; 
58  w.allocate(); 
59  (*w).setx(30); 
60  v.becomesAliasOf(w); 
61}

This revision adds a new method called detach. All detach does is to reset the pointer to 0. We also add checking logic to see if a pointer is NULL before changing it. If a pointer is not NULL, and we change it, the code throws an exception called CheckMemLeak.

In other words, in order to change a WhereIs to point to another object, the detach method should be invoked first. Otherwise, an exception is thrown at run-time.

The introduction of the “detachment” concept is critical. This makes it obvious to the programmer that whatever a WhereIs was pointing at may be lost.

Note that even the destructor checks if ptr is NULL. This is because the destruction of a WhereIs can potentially lead to loss of the last link to dynamically allocated object.

Even with the detach method, it does not prevent memory leak. It simply makes a programmer call detach first to expose the possibility of memory leak. However, a programmer may mistakenly call detach instead of nuke and lead to memory leak.

Note that even the destructor of WhereIs checks if ptr is 0. This forces a programmer to explicitly detach a WhereIs before it is destroyed.