Let ' s go,garbage Collector (vii)

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Gcptr overloads operator= () Twice:once for the assignment of a new address to a gcptr pointer, and once for the Assignme NT of one gcptr pointer to another. Both versions is shown here:

Overload assignment of Pointer to Gcptr.
Template <class T, int size>
T * gcptr<t, size>::operator= (t *t) {
List<gcinfo<t> >::iterator p;
First, decrement the reference count
For the memory currently being pointed to.
p = findptrinfo (addr);
p->refcount--;
Next, if the new address is already
Existent in the system, increment its
Count. Otherwise, create a new entry
For Gclist.
p = findptrinfo (t);
if (P! = Gclist.end ())
p->refcount++;
else {
Create and store this entry.
Gcinfo<t> gcobj (T, size);
Gclist.push_front (Gcobj);
}
addr = t; Store the address.
return t;
}
Overload assignment of Gcptr to Gcptr.
Template <class T, int size>
Gcptr<t, Size> & Gcptr<t, size>::operator= (gcptr &rv) {
List<gcinfo<t> >::iterator p;
First, decrement the reference count
For the memory currently being pointed to.
p = findptrinfo (addr);
p->refcount--;
Next, increment the reference count of
The new address.
p = findptrinfo (RV.ADDR);
p->refcount++; Increment ref count
Addr = rv.addr;//Store the address.
return RV;
}

The first overload of Operator= () handles assignments in which a gcptr pointer are on the left and an address are on the RI Ght. For example, it handles cases like the one shown here:

Gcptr<int> p;
// ...
p = new int (18);

Here, the address returned by new was assigned to P. When this happens, operator= (T *t) was called with the new address passed to T. First,the entry in Gclist for the memory that's currently being pointed to be found, and its reference count is decrement Ed. Next, a search of gclist is made for the new address. If It is found, its reference count is incremented. Otherwise, a new Gcinfo object is created for the new address, and this object are added to Gclist. Finally, the new address is stored in the invoking object ' s addr, and this address is returned.

The second overload of the assignment operator, operator= (Gcptr &rv), handles the following type of assignment:

Gcptr<int> p;
Gcptr<int> Q;
// ...
p = new int (88);
Q = p;

Here, both P and Q were gcptr pointers, and P is assigned to Q. This version of the assignment operator works much like the other. First, the entry in gclist for the memory which is currently being pointed to are found, and its reference count is Decremen Ted. Next, a search of gclist is made for the new address, which are contained in RV.ADDR, and their reference count is Incremente D. Then the invoking object ' s addr field was set to the address contained in RV.ADDR. Finally, the right-hand object is returned. This allows a chain of assignments to take place, such as:

p = q = w = Z;

There is one, and important point-to-make about the the-the-the-assignment operators work. As mentioned earlier in this chapter, it's technically possible to recycle memory as soon as their reference count drops to Zero, but doing so puts a extra overhead on each pointer operation. The overloaded assignment operators, the reference count for the memory previously pointed to by the left- Hand operand is simply decremented, and no further action is taken. Thus, the management overhead associated with actually releasing memory and performing maintenance on gclist are avoided. These actions is deferred to later, when the garbage collector runs. This approach makes for faster runtimes for the code that uses a gcptr. It also lets garbage collection take place at times that is (potentially) more convenient in terms of runtime performance .

The gcptr Copy Constructor

Because of the need to keep track of all pointer to allocated memory, the default copy constructor (which makes a bitwise Identical copy) cannot be used. Instead, gcptr must define is own copy constructor, which are shown here:

Copy constructor.
Gcptr (const gcptr &ob) {
List<gcinfo<t> >::iterator p;
p = findptrinfo (OB.ADDR);
p->refcount++; Increment ref count
addr = ob.addr;
ArraySize = ob.arraysize;
if (arraySize > 0) IsArray = true;
else IsArray = false;
#ifdef DISPLAY
cout << "constructing copy.";
if (IsArray)
cout << "Size is" << arraySize << Endl;
Else
cout << Endl;
#endif
}

Recall that a class ' copy constructor was invoked when a copy of an object was required, such as when an object is passed as An argument to a function, when an object is returned from a function, or if one object is used to initialize another. Gcptr ' s copy constructor duplicates the information contained in the original object. It also increments the reference count associated with the memory pointed to by the original object. When the copy is goes out of scope, this reference count would be decremented.

Actually, the extra work performed by the copy constructor are not usually necessary because the overloaded assignment oper Ators properly maintain the garbage collection list in most cases. However, there was a small number of cases in which the copy constructor was needed, such as when memory was allocated Insid e a function and a gcptr to the memory is returned.

The Pointer Operators and Conversion Function

Because gcptr is a pointer type, it must overload the pointer operators * AND–>, plus the indexing operator []. This is do by the functions shown. Given that it's the ability to overload these operators that makes it possible to create a new pointer type, it's Amazin G How simple they is.

Return a reference to the object pointed
To by this gcptr.
T &operator* () {
return *addr;
}
Return the address being pointed to.
T *operator-> () {return addr;}
Return a reference to the object at the
Index specified by I.
T &operator[] (int i) {
return addr[i];
}

The operator* () function returns a reference to the object pointed to by the addr field of the invoking Gcptr, operator–& gt; () Returns the address contained in addr, and operator[] returns a reference to the element specified by the index. Operator[] should is used only on gcptrs this point to allocated arrays.

As mentioned earlier, no pointer arithmetic is supported. For example, neither the + + nor The––operator is overloaded for gcptr. The reason is, the garbage collection mechanism assumes, a gcptr is pointing to the start of Allocated me Mory. If a gcptr could is incremented, for example and then when that pointer is garbage collected, the address used with delete W Ould be invalid.

You have the options if you need to perform operations that involve pointer arithmetic. First, if the gcptr is pointing to a allocated array, you can create a Iter that'll let's cycle through that array. This approach is described later. Second, you can convert a gcptr to a normal pointer by use of the T * conversion function defined by GCPTR. This function was shown here:

Conversion function to T *.
Operator t* () {return addr;}

This function returns a normal pointer, points to the address stored in addr. It can used like this.

gcptr<double> GCP = new double (99.2);
Double *p;
p = GCP; Now, p points to same memory as GCP
p++; Because P is a normal pointer, it can be incremented

In the preceding example, because P was a normal pointer, it can be manipulated on any-to-that-any-other pointer can. Of course, whether such manipulations yield meaningful results is dependent upon your application.

The main advantage of the conversion to T * are that it lets your use gcptrs in place of normal C + + pointers when working WI Th preexisting code that requires such pointers. For example, consider this sequence:

gcptr<char> str = new CHAR[80];
strcpy (str, "This is a Test");
cout << str << Endl;

Here, Str was a gcptr pointer to char, which is used in a call to strcpy (). Because strcpy () is expecting it arguments to being of type char *, the conversion to t* inside Gcptr is automatically invo Ked because, in this case, T is char. The same conversion was automatically invoked when Str was used in the cout statement. Thus, the conversion function enables Gcptrs to seamlessly integrate with existing C + + functions and classes.

Keep in mind, the T * pointer returned by this conversion does not participate in or affect garbage collection. Thus, it is possible for the allocated memory to be freed even if a regular C + + pointer is still pointing to it. So, use the conversion to t* Wisely––and infrequently.

The begin () and end () Functions

The Begin () and end () functions, shown next, is similar to their counterparts in the STL:

Return a Iter to the start of the allocated memory. Iter<t> begin () {
int size;
if (isarray) size = arraySize;
else size = 1;
return iter<t> (addr, addr, addr + size);
}
Return an allocated array with Iter to one past the end.
Iter<t> End () {
int size;
if (isarray) size = arraySize;
else size = 1;
return iter<t> (addr + size, addr, addr + size);
}

The Begin () function returns a Iter to the start of the allocated array pointed to by addr. The end () function returns a Iter to one past the end of the array. Although there is nothing so stops these functions from being called on a gcptr this points to a single object, their PU Rpose is to support operations on allocated arrays. (Obtaining a Iter to a single object was not harmful, just pointless.)

The shutdown () Function

If a program creates a circular reference of gcptrs and then when the program ends there would still be dynamically allocated Objects that need to being released. This is important because these objects might has destructors that need to be called. The shutdown () function handles this task. This function was registered by Atexit () when the first gcptr was created, as described earlier. This means, that it'll be called when the program terminates.

The shutdown () function is shown here:

//Clear gclist when program exits.
Template <class T, int size>
void Gcptr<t, Size>::shutdown () {
  if (gclistsize () = = 0) return; List is empty
  list<gcinfo<t> >::iterator p;
  for (P = gclist.begin (); P! = Gclist.end (); p++) {
    //Set All reference counts to zero
&nbs p;   p->refcount = 0;
 }
  #ifdef DISPLAY
    cout << "before collecting for shutdown () for"
  & nbsp;      << typeid (T). Name () << "/n";
  #endif
  collect ();
  #ifdef DISPLAY
    cout << "after collecting for shutdown () for"
   & nbsp;     << typeid (T). Name () << "/n";
  #endif
}

First, if the list is empty, which it'll normally be, then shutdown () simply returns. Otherwise, it sets to zero the reference counts of the entries, still exist in Gclist, and then it calls collect (). Recall that collect () releases any object and has a reference count of zero. Thus, setting the reference counts to zero ensures, then all objects would be freed.

Utility Functions

Gcptr ends by defining and utility functions. The first is gclistsize (), which returns the number of entries currently held in Gclist. The second is showlist (), which displays the contents of gclist. Neither of these is necessary for the implementation of a garbage collection pointer type, but they is useful when you w Ant to watch the operation of the garbage collector.

------------------------------------------------------------------

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.