[gnu.g++.bug] G++ Library Implementation Error

roberts@BORIS.TYMNET.COM (Michael Roberts) (12/07/89)

Dear Doug Lea -		dl@rocky.oswego.edu
		cc:	bug-g++@prep.ai.mit.edu

I am a new user of g++ version 1.35.0 and libg++ version 1.35.1.  I greatly
appreciate the flexible container classes in that library.  I have a possible
implementation error to report.

In the jargon of the GNU C++ Library manual, chapter 33, bottom of page 105,
the bug apears to be in d.del(k) of a particular Map class that I have used:
Integer.String.AVLMap.  The problem is that when I have a Map of 3 (or more)
nodes, deleting the second node causes the first node to have its contents
replaced by the contents of the departing second node; the contents of the
third (and later) node(s) are unchanged.  

I obtained the Map class in the following manner.  I generated the files
Integer.String.Map.h and Integer.String.Map.cc via the genclass call
	genclass -2 Integer val String ref Map
I generated the files Integer.String.AVLMap.h and Integer.String.AVLMap.cc
via the call
	genclass -2 Integer val String ref AVLMap

In order to get my code to compile, I had to make some changes to those files.
I have run diff on all four, yielding four difference files which I have
included in this e-mailing:
	Integer.String.Map.h.patch
	Integer.String.Map.cc.patch
	Integer.String.AVLMap.h.patch
	Integer.String.AVLMap.cc.patch
Those .patch files are stuffed into patch.shar at the end of this message.

Source code name (code appears below):

    g07.cc

Compiler command line:

    g++ -g g07.cc Integer.String.Map.o Integer.String.AVLMap.o

Execution and output:

    boris% a.out

    Key	Contents
    ___	________
    1	two
    3	three

    boris% 

So we put in 3 Strings, deleted the second one, and the contents of the first
one is overwritten with the second one's contents.  The output should have
been: 
    Key	Contents
    ___	________
    1	one
    3	three

I am running on a Sun 3/280 under SunOS 4.0.3

The g++ compiler is version 1.35.0 (as opposed to the library, which is
1.35.1).

I hope that's enough to help you find the problem.  Thanx!

-Mike

Michael G. Roberts 			| Internet: roberts@calvin.Tymnet.COM
BT Tymnet, Inc		 		| UUCP: {ames,sun}!oliveb!tymix!roberts
2560 North First Street 		| Voice: 408-922-7931
P.O.Box 49019, San Jose, CA 95161-9019 	| Fax:   408-922-6125

---------- The Source Code ----------

#include	<stream.h>
#include	"String.h"
#include	"Integer.h"
#include	"Integer.String.AVLMap.h"


main()
   {
    IntegerStringAVLMap ISM("empty");		// default contents "empty"

    ISM[Integer(1)] = String("one");
    ISM[Integer(2)] = String("two");
    ISM[Integer(3)] = String("three");

    ISM.del(Integer(2));			// HERE IT IS!!!

    cout << "\nKey	Contents\n___	________\n";
    // output all the strings in the IntegerStringAVLMap
    for (Pix i = ISM.first(); i != 0; ISM.next(i))
	cout << ISM.key(i) << "	" << ISM.contents(i) << "\n";
    cout << "\n";

    ISM.OK();
   } /* main */

---------- patch.shar ----------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Integer.String.AVLMap.cc.patch
#   Integer.String.AVLMap.h.patch Integer.String.Map.cc.patch
#   Integer.String.Map.h.patch
# Wrapped by roberts@boris on Wed Dec  6 14:33:49 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Integer.String.AVLMap.cc.patch' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Integer.String.AVLMap.cc.patch'\"
else
echo shar: Extracting \"'Integer.String.AVLMap.cc.patch'\" \(586 characters\)
sed "s/^X//" >'Integer.String.AVLMap.cc.patch' <<'END_OF_FILE'
X0a1,2
X> // 12-04-89 Added IntegerCMP
X> 
X25a28,29
X> #include "Integer.h"
X> #include "String.h"
X111a116,122
X> // From the usage of IntegerCMP results it is clear that cmp is to be
X> //  loaded with 0 iff key == t->item.  That is the semantics of !=.  But
X> //  there is the additional problem of the condition for returning a value
X> //  < 0, which I do not understand.  Perhaps compare(Integer&,Integer&) is
X> //  the better choice.  Yes!  <0 means arg1 < arg2.  This fits AVL being an
X> //  ordered Map.
X> inline int IntegerCMP(Integer& key, Integer& item) {return compare(key, item);}
END_OF_FILE
if test 586 -ne `wc -c <'Integer.String.AVLMap.cc.patch'`; then
    echo shar: \"'Integer.String.AVLMap.cc.patch'\" unpacked with wrong size!
fi
# end of 'Integer.String.AVLMap.cc.patch'
fi
if test -f 'Integer.String.AVLMap.h.patch' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Integer.String.AVLMap.h.patch'\"
else
echo shar: Extracting \"'Integer.String.AVLMap.h.patch'\" \(0 characters\)
sed "s/^X//" >'Integer.String.AVLMap.h.patch' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'Integer.String.AVLMap.h.patch'`; then
    echo shar: \"'Integer.String.AVLMap.h.patch'\" unpacked with wrong size!
fi
# end of 'Integer.String.AVLMap.h.patch'
fi
if test -f 'Integer.String.Map.cc.patch' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Integer.String.Map.cc.patch'\"
else
echo shar: Extracting \"'Integer.String.Map.cc.patch'\" \(622 characters\)
sed "s/^X//" >'Integer.String.Map.cc.patch' <<'END_OF_FILE'
X0a1,2
X> // 12-04-89 Corrected ::seek
X> 
X24a27,28
X> #include "Integer.h"
X> #include "String.h"
X41a46
X> #if 0
X42a48,58
X> #else
X>   // This loop advances the Pix index i from first to last, each time checking
X>   //  that have not reached either the end of the Map or the desired key value
X>   //  item.  The missing function IntegerEQ must be supplied.  Integer.h has
X>   //  the following functions to choose from:
X>   //	compare		signed comparison
X>   //	ucompare	unsigned comparison		not appropriate here
X>   //	==
X>   //	!=						I'll try this one
X>   for (Pix i = first(); i != 0 && (key(i) != item); next(i));
X> #endif
END_OF_FILE
if test 622 -ne `wc -c <'Integer.String.Map.cc.patch'`; then
    echo shar: \"'Integer.String.Map.cc.patch'\" unpacked with wrong size!
fi
# end of 'Integer.String.Map.cc.patch'
fi
if test -f 'Integer.String.Map.h.patch' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Integer.String.Map.h.patch'\"
else
echo shar: Extracting \"'Integer.String.Map.h.patch'\" \(94 characters\)
sed "s/^X//" >'Integer.String.Map.h.patch' <<'END_OF_FILE'
X30c30,31
X< #include "Integer.defs.h"
X---
X> //#include "Integer.defs.h"
X> #include "Integer.h"
END_OF_FILE
if test 94 -ne `wc -c <'Integer.String.Map.h.patch'`; then
    echo shar: \"'Integer.String.Map.h.patch'\" unpacked with wrong size!
fi
# end of 'Integer.String.Map.h.patch'
fi
echo shar: End of shell archive.
exit 0