In this part we implement a Garbage Collection with C++.
Keywords:
-Lifetime:
The period during witch an object exist, is the “Lifetime†of this object.
-Access Path:
“Access Path†to an object is the path that can access to an object.
-Garbage:
If all Access Paths to a Data Object (DO) loses, this Data Object is like “Garbage†in the memory.
-Dangling Reference:
If “Lifetime†of each Data Object (DO) was finished, when there is at least one “Access Path†to it, all Access Paths are “Dangling Referenceâ€.
Example of Garbage:
int * pi1 = new int; // first DO
int * pi2 = new int; // second DO
pi2 = pi1; // now pi1 and pi2 refer to first DO
// and the all access path to the second DO loses;
Example of Dangling Reference:
int * pi = new int; // first DO
delete pi;
...
//use the pi makes runtime error
Now we want to solve garbage problem, which named Garbage Collection.
One of the ways that solve this problem is:
1.Delete all data objects that create using new or malloc.
2.When delete a reference to a data object don’t forget assign NULL to the pointer.
But I write a class in C++ that if I and you forgot the two rules above.
In this Class I use below techniques and if you don’t know one of them I suggested that you learn these techniques before reading the code.
-Templates
-Smart Pointers
-Overloading operators
-And other object oriented techniques.
template<typename T>
class CDataPacket
{
private:
int RefNum;
public:
T* pData;
CDataPacket();
~CDataPacket();
void DecRef();
void IncRef();
};
This class provides a data object that can be reference to a user data object, and count the references to it, and increment and decrement the reference counter.
In this object when the references counter equal to zero, user data object and this object deleted.
template<typename T>
class CPtr
{
private:
CDataPacket<T> * Refs;
public:
~CPtr();
CPtr();
T* operator->();
T & operator*();
operator T*();
CPtr<T>& operator = ( T* p);
CPtr<T>& operator = ( CPtr<T>& p);
};
This class provide an interface for users that can work with this object like the pointers, also this class administrate the assignments, because in assignments references increment and decrement.
Below is the implementation of above classes.
template<typename T>
void CDataPacket<T>::DecRef()
{
if (RefNum == 0) return;
RefNum--;
if (RefNum == 0)
delete this;
}
template<typename T>
void CDataPacket<T>::IncRef()
{
RefNum++;
}
template<typename T>
CDataPacket<T>::CDataPacket()
{
pData = NULL;
RefNum = 0;
}
template<typename T>
CDataPacket<T>::~CDataPacket()
{
delete pData;
}
template<typename T>
CPtr<T>& CPtr<T>::operator= ( T* p)
{
if ( Refs)
Refs->DecRef();
Refs = new CDataPacket<T>;
Refs->pData = p;
Refs->IncRef();
return *this;
}
template<typename T>
CPtr<T>& CPtr<T>::operator= ( CPtr<T>& p)
{
if ( Refs)
Refs->DecRef();
Refs = p.Refs;
Refs->IncRef();
return *this;
}
template<typename T>
CPtr<T>::~CPtr()
{
Refs->DecRef();
}
template<typename T>
CPtr<T>::CPtr()
{
Refs = NULL;
}
template<typename T>
T* CPtr<T>::operator ->()
{
return Refs->pData;
}
template<typename T>
T& CPtr<T>::operator *()
{
return *(Refs->pData);
}
template<typename T>
CPtr<T>::operator T*()
{
return Refs->pData;
}
Example of using these classes:
Ex1:
void main()
{
CPtr<int> pii;
pii = new int[10];
pii[0]=0;
pii[2]=10;
cout << pii[0] << endl;
cout << pii[2] << endl;
}
Output:
0
10
Ex2:
class test
{
private:
int data;
public:
test(int i){ data = i;};
~test(){ cout << " class #"<<data<<" destroyed."<< endl; };
void DoSomeThing(){ cout << " class #"<<data<<" doing something."<< endl; };
};
void main()
{
CPtr<test> ts,ts1,ts2;
ts = new test(0);
ts1 = new test(1);
ts2 = new test(2);
ts->DoSomeThing(); // output in line 1
ts1->DoSomeThing(); // output in line 2
ts2->DoSomeThing(); // output in line 3
ts = ts1; // output in line 4
ts1 = ts2;
ts->DoSomeThing(); // output in line 5
ts1->DoSomeThing(); // output in line 6
ts2->DoSomeThing(); // output in line 7
ts1 = ts;
ts->DoSomeThing(); // output in line 8
ts1->DoSomeThing(); // output in line 9
ts2->DoSomeThing(); // output in line 10
(*ts).DoSomeThing(); // output in line 11
} // output in line 12,13
Output:
1: class #0 doing something.
2: class #1 doing something.
3: class #2 doing something.
4: class #0 destroyed.
5: class #1 doing something.
6: class #2 doing something.
7: class #2 doing something.
8: class #1 doing something.
9: class #1 doing something.
10: class #2 doing something.
11: class #1 doing something.
12: class #2 destroyed.
13: class #1 destroyed.
Have a Goooood Day, with more errorless programming.