home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / cplus / 18667 < prev    next >
Encoding:
Text File  |  1993-01-04  |  4.6 KB  |  117 lines

  1. Newsgroups: comp.lang.c++
  2. Path: sparky!uunet!newsgate.watson.ibm.com!yktnews!admin!wo0z!lwloen
  3. From: lwloen@rchland.vnet.ibm.com (Larry Loen)
  4. Subject: Small objs & When/whether to overload "new" with statics
  5. Sender: news@rchland.ibm.com
  6. Message-ID: <1993Jan04.162941.13841@rchland.ibm.com>
  7. Date: Mon, 04 Jan 1993 16:29:41 GMT
  8. Reply-To: lwloen@rchland.vnet.ibm.com
  9. Disclaimer: This posting represents the poster's views, not necessarily those of IBM
  10. Nntp-Posting-Host: wo0z.rchland.ibm.com
  11. Organization: IBM Rochester
  12. Lines: 103
  13.  
  14. Suppose I have a small "helper" class object like this:
  15.  
  16. class BitRef   {  // handles assign of bits within char (actually, bit) arrays
  17.   int loc;        // bit location (offset) 0 origin, 0 h.o.bit
  18.   char* data;     // pointer to some character (actually bit) array
  19.   static char cvt[9];
  20.   static char cvtn[9];
  21.   //  cvt[] = { 128,64,32,16,8,4,2,1 }; elsewhere
  22.   //  cvtn[]= { 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE }
  23.   int GetBit() const  { // return bit at current loc
  24.              int i,j; char k; 
  25.              i=loc/8; j=(loc&7);
  26.              k= (data[i]& cvt[j]);
  27.              if (k!=0) return 1; else return 0;
  28.              };    // end GetBit()
  29.  public:
  30.   BitRef(int l,char *d) : loc(l),data(d) {};
  31.   BitRef& operator = (int q) 
  32.            { int i,j; char k;
  33.              i=loc/8; j=(loc&7);
  34.              k=cvt[j];
  35.              if (q&1) 
  36.                data[i]|=k;
  37.              else               
  38.                data[i]&=(cvtn[j]); 
  39.              return (*this); };
  40.   BitRef& operator = (const BitRef &q)  
  41.            { int i; i=q.GetBit();
  42.              (*this)=i; return (*this); };
  43.   // Note:  default copy constructor and destructor are correct
  44.  };  // end BitRef
  45.  
  46. The point of "BitRef" is to be returned as a temporary in a variety
  47. of "bit" objects.  For instance:
  48.  
  49.  class halfword  {  // 16 bits on many machines
  50.    char[2] data;
  51.   public
  52.    BitRef operator[] (int i) { return BitRef(i,data); };
  53.    // etc.
  54. };
  55.  
  56. and then one codes:
  57.  
  58.   halfword x;
  59.   x = 13;
  60.   x[0]= 1;  // etc.
  61.  
  62. Now, I am less interested in the particular virtues and vices of 
  63. BitRef per se than in what to do _in general_ with helper objects of
  64. that kind.  Note carefully that in the normal course of events, BitRef
  65. will never be formally declared.  It will arise, normally, as a temporary
  66. in various objects' operator[].  There are many such potential objects.
  67.  
  68. Optimizing such objects can be important, especially if they "help" 
  69. functions like operator[], because they may appear in inner "for" loops.
  70.  
  71. I especially wonder about "new" and "delete".
  72.  
  73. For machines with enough registers, one presumes that the above code 
  74. could work out fairly nicely, as is.  Each data element of an instance 
  75. of BitRef could imaginably have both of its small pieces optimized into 
  76. a register, especially since the compiler, since it creates it, is in 
  77. full control of how long the instances live.
  78.  
  79. For a PC-type machine, however, such optimization seems unlikely (is
  80. that so?).  Therefore, _if_ the compiler's generation of "temps" uses
  81. new and delete, one would be tempted to add something like the following
  82. to BitRef
  83.  
  84.   static short int  two[2];
  85.   static BitRef *twop[2];
  86.  
  87. Their init would set both members of two to "false" and twop to null.
  88. The overloaded new would see if either value of "two" were false.  If
  89. either was, it would know it they not in use and return a non-null value of
  90. the corresponding twop.  Delete would simply check twop and mark the
  91. corresponding member of two "false" if it matched.  If there were more
  92. than two outstanding BitRefs, the normal new/delete would be used.
  93.  
  94. The upshot of this is that there typically be only two calls to the
  95. ::new function and very few to ::delete, because few expressions would
  96. need more than two BitRefs to complete the work.  And, the memory
  97. allocation overhead could be generally dispensed with, which may be worth
  98. a lot of performance.
  99.  
  100. On the other hand, if the compiler were smart enough to add its temps to
  101. the regular program push/pop stack (thus avoiding new and delete altogether),
  102. there would be no net advantage to the overload, even with no optimization.
  103. Which is typically done?
  104.  
  105. In the case of BitRef itself, the optimization question is of some interest,
  106. because it may be sensible to separate "loc" into two values in the object,
  107. passing them into the constructor, up front, which may aid run time 
  108. performance at least some of the time (eg halfword[4]), if one did not wipe 
  109. out the gains by introducing added memory allocation by exceeding some 
  110. internal threshhold or other.
  111.  
  112. Is all/any of this reasonable analysis?
  113.  
  114. -- 
  115.    Larry W. Loen        |  My Opinions are decidedly my own, so please
  116.                         |  do not attribute them to my employer
  117.