Topic: STL list::merge


Author: khan@xraylith.wisc.edu (Mumit Khan)
Date: 1995/06/05
Raw View
In article <D9B3sv.5oM@ucc.su.oz.au>,
John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
>In article <3prcmp$cj4@giga.bga.com>, Jamshid Afshar <jamshid@ses.com> wrote:
>>I strongly disagree.  One of the beauties of the STL is that code
>>written using it is not verbose, especially compared to other
>>libraries (e.g., RogueWave's RWTValHashDictionary and
>>RWTValHashDictionaryIterator).
>
> I beg to differ. The code I have written using STL is
>so damn long winded it is almost unreadable. This is not
>the fault of STL but of the C++ language itself.
>I have _simple_ examples where it takes 80 characters
>to declare an iterator: the indexed loop

My longest so far was *longer* than 80 characters! granted it was a cooked
up example to show someone, but it could happen. I've started typedef'ing
everything in sight, esp the recursive templates, and using that to define
the iterators; the downside is obvious: the namespace pollution, but the
upside, other than shorter meaningful names, is that the user of the class
doesn't care if my polygon uses a deque or a vector to store the points.

IMO the problem is not *just* with iterators (and hence a simple "iterator
shortening" scheme won't make it go away), but with C++ templated data
type declarations:
    void foo(const stack<deque<map<string, X, less<string> > >& dictstack);

Until more compilers implement namespaces, I'd just have to stick to
typedefs. Readable code is worth a lot.

mumit -- khan@xraylith.wisc.edu
http://www.xraylith.wisc.edu/~khan/





Author: horstman@sjsumcs.sjsu.edu (Cay Horstmann)
Date: 1995/05/24
Raw View
Jamshid Afshar (jamshid@ses.com) wrote:

: I believe the extra danger in the cases where set<T> doesn't work is
: worth its simplicity in the common case.  After all, users will be
: using set<string> instead of set<char*>.  In the case where they do
: make a container of pointers, the user not only has to be taught to
: specify a comparator, but to handle the allocation and deallocation of
: the objects.

Neither set<char*> nor set<string> occur an awful lot in practice. I just
used set<char*> because I could make a striking 4-line example of
surprising STL behavior.

The real question is whether you are likely to make a container<X*> or a
container<X> for a class X. I looked through some code of mine and Borland
OWL. The container<X*> seem to be dominant. And for them the STL default
of using < for comparison is wrong. I am not in favor of supplying a
default that is wrong in the majority of the cases.

Cay





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/05/26
Raw View
Cay Horstmann (horstman@sjsumcs.sjsu.edu) wrote:
|> Jamshid Afshar (jamshid@ses.com) wrote:

|> : I believe the extra danger in the cases where set<T> doesn't work is
|> : worth its simplicity in the common case.  After all, users will be
|> : using set<string> instead of set<char*>.  In the case where they do
|> : make a container of pointers, the user not only has to be taught to
|> : specify a comparator, but to handle the allocation and deallocation of
|> : the objects.

|> Neither set<char*> nor set<string> occur an awful lot in practice. I just
|> used set<char*> because I could make a striking 4-line example of
|> surprising STL behavior.

|> The real question is whether you are likely to make a container<X*> or a
|> container<X> for a class X. I looked through some code of mine and Borland
|> OWL. The container<X*> seem to be dominant. And for them the STL default
|> of using < for comparison is wrong. I am not in favor of supplying a
|> default that is wrong in the majority of the cases.

This seems surprising to me.  When I look through my own code, there
isn't a single instance of contaniner<X*>.  (There are a number of cases
of container< RefCntPtr< X > >, however.)

Who owns the object in these cases?  It sounds like an invitation to
memory leaks to me.  (Note that the default behavior of the STL classes
does not delete the objects pointed to, either.)
--
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
                             --Beratung in industrieller Datenverarbeitung





Author: Kalyan Kolachala <kal@chromatic.com>
Date: 1995/05/27
Raw View
kanze@gabi-soft.fr (J. Kanze) wrote:
>Cay Horstmann (horstman@sjsumcs.sjsu.edu) wrote:
>|> Jamshid Afshar (jamshid@ses.com) wrote:
>

>|> The real question is whether you are likely to make a
container<X*> or a
>|> container<X> for a class X. I looked through some code of
mine and Borland
>|> OWL. The container<X*> seem to be dominant. And for them
the STL default
>|> of using < for comparison is wrong. I am not in favor of
supplying a
>|> default that is wrong in the majority of the cases.
>

STL also provides for a member template version of merge

template<class Compare> void merge(list<T,Allocator>& x,
Compare comp);

Thus for list<X*> or for any other type where operator "<"
is not desired for comparison the member template version
can be used.

- Kalyan






Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/28
Raw View
In article <3prcmp$cj4@giga.bga.com>, Jamshid Afshar <jamshid@ses.com> wrote:
>>
>>Hence my recommendation: Don't make ANY template argument default to
>>less<T>.  Don't use < in ANY template whatnot<T>. You'll get guaranteed
>>nonsense when T is a pointer.
>
>I strongly disagree.  One of the beauties of the STL is that code
>written using it is not verbose, especially compared to other
>libraries (e.g., RogueWave's RWTValHashDictionary and
>RWTValHashDictionaryIterator).

 I beg to differ. The code I have written using STL is
so damn long winded it is almost unreadable. This is not
the fault of STL but of the C++ language itself.
I have _simple_ examples where it takes 80 characters
to declare an iterator: the indexed loop

 for(int i=0; i<x.len(); ++i) ...

in STLese is written

 for(vector<X>::iterator i = x.begin(); i<x.end(); ++i) ...

Now try that with _longer names_ and with two levels of
indirection and you will see what I mean. What is required
I think is

 for(declare i = x.begin(); ...

where "declare i = expression" declares "i" to have the type
of "expression". A second extension "typeof(expr)" is
more general.

This greatly simplifies STL. Instead of rubbish like:

 class Container {
  typedef X iterator;
  typedef X const const_iterator;
  typedef Y value;
  ...

we can get rid of the typedefs. Instead, you can discover the
type of an iterator by

 typeof(it)

and the type of a value by

 typeof(*it)

Oh, and guess what? This WORKS for arrays, whereas the
notation

 Container::iterator

does not. At least two compilers -- Metaware and GNU --
support "typeof", it is clearly trivial to implement.

BTW: I do agree with you that STL provides _simpler_ code
than almost any other library -- but it does require
a lot of syntax to say these simple things.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: jamshid@ses.com (Jamshid Afshar)
Date: 1995/05/23
Raw View
In article <3otl77$4ee@jupiter.SJSU.EDU>,
Cay Horstmann <horstman@sjsumcs.sjsu.edu> wrote:
>John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>: 2) < is not required for T unless you use < on the container,
>: if you do and the comparison compares entities which are not
>: comparable the results are undefined.
>
>It is pretty tough NOT to use < on a container like set. Consider the
>following code example. [...]
 set<char*> s;
>Sure, it is the user's fault--the user should have used set<char*, C>
>where C is some comparison function(oid) that compares strings by something
>other than the offset portion of their address.
>
>Hence my recommendation: Don't make ANY template argument default to
>less<T>.  Don't use < in ANY template whatnot<T>. You'll get guaranteed
>nonsense when T is a pointer.

I strongly disagree.  One of the beauties of the STL is that code
written using it is not verbose, especially compared to other
libraries (e.g., RogueWave's RWTValHashDictionary and
RWTValHashDictionaryIterator).  In fact when I wrote my container
class library (years ago, before default template args) I derived my
OrdSet<T> class template from OrdSetComp<T,Comp>.  I didn't want to
always specify the Comparator class, but I wanted the ability to use a
non-default comparator when necessary.

I believe the extra danger in the cases where set<T> doesn't work is
worth its simplicity in the common case.  After all, users will be
using set<string> instead of set<char*>.  In the case where they do
make a container of pointers, the user not only has to be taught to
specify a comparator, but to handle the allocation and deallocation of
the objects.

Jamshid Afshar
jamshid@ses.com





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/17
Raw View
In article <3p5qv0$4o1@hustle.rahul.net>,
Ronald F. Guilmette <rfg@rahul.net> wrote:
>>2) < is not required for T unless you use < on the container,
>>if you do and the comparison compares entities which are not
>>comparable the results are undefined.
>
>Undefined at compile-time or undefined at run-time?
>
>(It makes a difference.)
>

 Yes. I think the wording is unclear on this.
I believe the intent is:

 a) if < is not defined on T, then using < on the
 container yields a compile time error (required
 diagnositic)

 b) if operator < is specified with arguments
 taking two T and is applied for two T which are
 not comparable, the results of the comparison are
 undefined at run time.

-- because this seems to be how templates work.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: jamshid@ses.com (Jamshid Afshar)
Date: 1995/05/12
Raw View
In article <D8EoJG.9w8@ucc.su.OZ.AU>,
John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
> The response from Alex Stepanov is as follows:
>
>1) T() is not required for the value type of a container.

Are there plans to explicitly define what T operations are required by
the standard C++ template classes and functions?  Even though a
template parameter "constraints" feature was never added to C++, I
think the standard should document the constraints on T ala D&E
15.4.2.  Well, I guess that's a bit hard or would end up being verbose
because each member function might also have its own constraints on T.
Maybe there could be a general constraint section for each class
template and each function could list any additional constraints if
that function (or an overloaded function of the same name?) is used.

>2) < is not required for T unless you use < on the container,
>if you do and the comparison compares entities which are not
>comparable the results are undefined.
>
>3) I forgot to ask but by extension algorithms like "merge"
>and "sort" are supposed to have preconditions  that <
>is defined and totally orders the elements -- so again the
>responsibility is on the user to ensure these algorithms
>are not called unless T has a < totally ordering the
>elements of the container.

Well, there are two list::merge() and two list::sort() functions.  One
of each uses "<" and the other is a member template taking a Compare
object (see Draft 20-20).  The same is true for the merge() and sort()
non-member function templates.

Jamshid Afshar
jamshid@ses.com





Author: "Ronald F. Guilmette" <rfg@rahul.net>
Date: 1995/05/14
Raw View
In article <D8EoJG.9w8@ucc.su.OZ.AU>,
John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
>In article <D8E2q4.Kw2@ucc.su.OZ.AU>,
>John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
>>>
>>>Of course, I can define < for Employee. But suppose I had used a
>>>list<Employee*> instead. There already is a < defined for pointers, and
>>>I can't change it, nor can STL use it. < is only defined for pointers into
>>>the same array.
>>>
>>>What is the intention of the standard in this regard? Thanks for any illumi-
>>>nation!
>>
>> I have posed this question to the committee on the -lib refector
>>and will post a summary of responses there to this group.
>
> The response from Alex Stepanov is as follows:
>
>1) T() is not required for the value type of a container.
>
>2) < is not required for T unless you use < on the container,
>if you do and the comparison compares entities which are not
>comparable the results are undefined.

Undefined at compile-time or undefined at run-time?

(It makes a difference.)

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- E-mail: rfg@segfault.us.com ----------- Purveyors of Compiler Test ----
---- finger: rfg@rahul.net ----------------- Suites and Bullet-Proof Shoes -





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/11
Raw View
In article <D8E2q4.Kw2@ucc.su.OZ.AU>,
John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
>>
>>Of course, I can define < for Employee. But suppose I had used a
>>list<Employee*> instead. There already is a < defined for pointers, and
>>I can't change it, nor can STL use it. < is only defined for pointers into
>>the same array.
>>
>>What is the intention of the standard in this regard? Thanks for any illumi-
>>nation!
>
> I have posed this question to the committee on the -lib refector
>and will post a summary of responses there to this group.

 The response from Alex Stepanov is as follows:

1) T() is not required for the value type of a container.

2) < is not required for T unless you use < on the container,
if you do and the comparison compares entities which are not
comparable the results are undefined.

3) I forgot to ask but by extension algorithms like "merge"
and "sort" are supposed to have preconditions  that <
is defined and totally orders the elements -- so again the
responsibility is on the user to ensure these algorithms
are not called unless T has a < totally ordering the
elements of the container.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: jamshid@ses.com (Jamshid Afshar)
Date: 1995/05/11
Raw View
In article <3ojgfl$sun@jupiter.SJSU.EDU>,
Cay Horstmann <horstman@sjsumcs.sjsu.edu> wrote:
>I just ran into grief when trying to make an STL list<Employee>.
>I can't do it--list::merge doesn't compile because I didn't
>define an operator< on employees.
>
>Actually, I shouldn't blame STL. The fault is with my compiler that
>instantiates the unused list::merge.

As a compiler bug workaround you might try defining an empty
specialization of list<Employee>::merge() (maybe inline right after
the definition of class Employee).

>But then again I do blame STL. The entire concept doesn't make sense.
>Merge shouldn't use the hardwired <. It should take a comparison function
>object, with less<Employee> as the default.

I can understand why

 bool operator<( const list<T>&, const list<T>&);

would have to hard-code the use of the "<" operator on the T's (since
a Comparator object or class couldn't be specified), but why can't
list<T>::merge() be a member template?

Let me check the draft... (ooh, reading/searching the draft in .pdf
format is slow but quite nice).  There IS a list::merge() that is a
member template taking a Compare class as a parameter (p 23-20):

 template<class T, class Allocator = allocator>
 class list {
    void merge(list<T,Allocator>& x);
    template <class Compare>
       void merge(list<T,Allocator>& x, Compare comp);
 };

So, once compilers start implementing member templates you'll be able
to merge() a couple of list<T>'s using something other than the "<"
operator.  Actually, you can already do this using the non-member
merge():

template <class InputIterator1, class InputIterator2, class OutputIterator,
   class Compare>
OutputIterator merge(InputIterator1 first1, InputIterator1 last1,
       InputIterator2 first2, InputIterator2 last2,
       OutputIterator result, Compare comp);

>Of course, I can define < for Employee. But suppose I had used a
>list<Employee*> instead. There already is a < defined for pointers, and
>I can't change it, nor can STL use it. < is only defined for pointers into
>the same array.

It seems like the STL designers were very careful not to box users in
to particular comparison functions or syntaxes.  They were also
careful to not make any unnecessary requirements on the element types
put into STL containers.

Jamshid Afshar
jamshid@ses.com





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/11
Raw View
In article <3ojgfl$sun@jupiter.SJSU.EDU>,
Cay Horstmann <horstman@sjsumcs.sjsu.edu> wrote:
>I just ran into grief when trying to make an STL list<Employee>.
>I can't do it--list::merge doesn't compile because I didn't
>define an operator< on employees.
>
>Actually, I shouldn't blame STL. The fault is with my compiler that
>instantiates the unused list::merge.
>
>But then again I do blame STL. The entire concept doesn't make sense.
>Merge shouldn't use the hardwired <. It should take a comparison function
>object, with less<Employee> as the default.
>
>Of course, I can define < for Employee. But suppose I had used a
>list<Employee*> instead. There already is a < defined for pointers, and
>I can't change it, nor can STL use it. < is only defined for pointers into
>the same array.
>
>What is the intention of the standard in this regard? Thanks for any illumi-
>nation!

 I have posed this question to the committee on the -lib refector
and will post a summary of responses there to this group.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: horstman@sjsumcs.sjsu.edu (Cay Horstmann)
Date: 1995/05/11
Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
: > I have posed this question to the committee on the -lib refector
: >and will post a summary of responses there to this group.

Thanks!

:  The response from Alex Stepanov is as follows:

: 2) < is not required for T unless you use < on the container,
: if you do and the comparison compares entities which are not
: comparable the results are undefined.

It is pretty tough NOT to use < on a container like set. Consider the
following code example.

int main()
{  set<char*> s;

   s.insert(new char[10]);
   s.insert(new char[20]);
   cout << s.size() << endl;
}

This program will print "2" when you compile it on a PC with small memory
model, and it will print "1" in large memory model.

Sure, it is the user's fault--the user should have used set<char*, C>
where C is some comparison function(oid) that compares strings by something
other than the offset portion of their address.

Hence my recommendation: Don't make ANY template argument default to
less<T>.  Don't use < in ANY template whatnot<T>. You'll get guaranteed
nonsense when T is a pointer.

Cay
horstman@cs.sjsu.edu






Author: horstman@sjsumcs.sjsu.edu (Cay Horstmann)
Date: 1995/05/07
Raw View
I just ran into grief when trying to make an STL list<Employee>.
I can't do it--list::merge doesn't compile because I didn't
define an operator< on employees.

Actually, I shouldn't blame STL. The fault is with my compiler that
instantiates the unused list::merge.

But then again I do blame STL. The entire concept doesn't make sense.
Merge shouldn't use the hardwired <. It should take a comparison function
object, with less<Employee> as the default.

Of course, I can define < for Employee. But suppose I had used a
list<Employee*> instead. There already is a < defined for pointers, and
I can't change it, nor can STL use it. < is only defined for pointers into
the same array.

What is the intention of the standard in this regard? Thanks for any illumi-
nation!

Cay
horstman@cs.sjsu.edu