home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / std / cplus / 1772 < prev    next >
Encoding:
Text File  |  1992-12-14  |  4.9 KB  |  136 lines

  1. Newsgroups: comp.std.c++
  2. Path: sparky!uunet!mcsun!sunic!news.lth.se!dag
  3. From: dag@bellman.control.lth.se (Dag Bruck)
  4. Subject: Pointer comparisons and templates
  5. Message-ID: <1992Dec14.075853.3399@lth.se>
  6. Summary: Example with generic binary search tree class
  7. Sender: news@lth.se
  8. Organization: Department of Automatic Control, Lund, Sweden
  9. References: <1992Dec8.103218.27689@lth.se> <1992Dec8.173855.18153@meaddata.com> <1992Dec9.075125.22405@lth.se> <1992Dec12.154918.2220@ucc.su.OZ.AU>
  10. Date: Mon, 14 Dec 1992 07:58:53 GMT
  11. Lines: 123
  12.  
  13. In the recent discussion on pointer comparisons, Fergus Hendersson
  14. suggested adding a standard library function ptrcmp() instead of
  15. extending the definitions of "<" and ">" for pointers.  I think we
  16. also agreed on a reasonable relationship between ptrcmp() and the
  17. relational operators.
  18.  
  19. While I think ptrcmp() is better than nothing, I still think extending
  20. the definition of the relational operators is far better.  Consider
  21. this template class (the code may be wrong, I'm just inventing an
  22. almost real example for the purpose of discussion):
  23.  
  24.     template <class T>
  25.     class Tree {
  26.     private:
  27.         struct Node {
  28.             T element;
  29.             Node* left;
  30.             Node* right;
  31.             Node(const T& e) : element(e),left(0),right(0) {}
  32.             ~Node() { delete left; delete right; }
  33.         };
  34.         Node* root;
  35.         T& InsertElement(Node*& root, const T& element);
  36.     public:
  37.         Tree() : root(0) {}
  38.         ~Tree() { delete root; }
  39.         T& Insert(const T& e) { return InsertElement(root, e); }
  40.     };
  41.  
  42. Most of the template class Tree is a skeleton around InsertElement()
  43. which is the function that actually does the job:
  44.  
  45.     template <class T>
  46.     T& Tree<T>::InsertElement(Node*& root, const T& element)
  47.     {
  48.         if (root == 0) {
  49.             root = new Node(element);
  50.             return root->element;
  51.         }
  52.         if (element < root->element)
  53.             return InsertElement(root->left, element);
  54.         if (root->element < element)
  55.             return InsertElement(root->right, element);
  56.         return root->element;
  57.     }
  58.  
  59. Note that a copy of the element argument is inserted into the tree,
  60. and that InsertElement() always returns a reference to this copy.
  61.  
  62. Now, here's the problem: this implementation works fine for all
  63. element types that have an "operator < ()" including plain built-in
  64. types and many user-defined types.  However, it is not guaranteed to
  65. work with pointer elements for reasons we have discussed before.
  66.  
  67. They way around this problem is to make a specialization for pointers:
  68.  
  69.     void*& Tree<void*>::InsertElement(Node*& root, const void*& element)
  70.     {
  71.         if (root == 0) {
  72.             root = new Node(element);
  73.             return root->element;
  74.         }
  75.         if (ptrcmp(element, root->element) < 0)        // ****
  76.             return InsertElement(root->left, element);
  77.         if (ptrcmp(root->element, element) < 0)        // ****
  78.             return InsertElement(root->right, element);
  79.         return root->element;
  80.     }
  81.  
  82. The changes are marked with ****, and the function signature is also
  83. changed, of course.  We must also make a specialized Tree class for
  84. pointers to do the appropriate type casting to/from void*.
  85.  
  86.     template <class T>
  87.     class PtrTree : private Tree<void*> {
  88.     public:
  89.         PtrTree() {}
  90.         ~PtrTree {}
  91.         T*& Insert(const T*& e)
  92.             { return (T*&) Tree<void*>::Insert(e); }
  93.     };
  94.  
  95. I think this covers it all, but I'm not quite sure if the derivation
  96. should be public instead.  In any case, here are a few pros and cons:
  97.  
  98. 1.  It can be done with a minimal change to the language (adding a
  99. standard library function).  It can also be done in a non-portable way
  100. without the library function.
  101.  
  102. 2.  In the general case we cannot use the trick of converting to a
  103. long integer, but it could be used in the specialization for void*.
  104.  
  105. 3.  The programmer using class Tree must remember to use a different
  106. class for pointers.  There is no type checking that prevents the user
  107. from using Tree<Foo*> -- it will compile fine but produce the wrong
  108. results on some machines.
  109.  
  110. 4.  The implementor and maintainer of similar classes must remember to
  111. handle pointers in a special way.  The public interface of each data
  112. structure must be replicated, and each class requires at least a
  113. specialization for void*.
  114.  
  115. I regard (3) is biggest problem, in particular as there is no way (as
  116. far as I know) to diagnose the problem.   It may work fine on some
  117. machines, and then break when you port the code to a new machine or a
  118. new memory model on the same machine.
  119.  
  120. I think (4) is a lesser problem because you only have to get it right
  121. every time you write or modify a general data structure, not every
  122. time you use it.  I think the handling of pointers adds a significant
  123. complexity to a rather simple data structure "right out of the
  124. textbook."
  125.  
  126. Any comments or suggestions would be welcome.  I would be particularly
  127. happy if you could show that I have described a problem that in fact
  128. does not exist if you use a suitable programming style.
  129.  
  130. Dag Bruck
  131. --
  132. Department of Automatic Control        E-mail: dag@control.lth.se
  133. Lund Institute of Technology
  134. P. O. Box 118                Phone:    +46 46-104287
  135. S-221 00 Lund, SWEDEN            Fax:    +46 46-138118
  136.