Topic: An STL helper -- and template and type shenanigans


Author: phalpern@truffle.ultranet.com (Pablo Halpern)
Date: 1996/02/21
Raw View
kanze@gabi.gabi-soft.fr (J. Kanze) wrote:

>In article <4eto87$9kf@hermes.synopsys.com> jbuck@Synopsys.COM (Joe
>Buck) writes:
>> The *language*, not just STL, requires copy constructors that actually
>> copy.  The language automatically uses the copy constructor whenever it
>> needs to make a copy.  The copy constructor is used to return objects from
>> functions and to pass them in by value.  This usaga assumes that you get
>> an actual copy.  Copy constructors can be optimized away in certain
>> circumstances.  Again, this optimization works based on the assumption
>> that a copy constructor does a copy, so you can avoid the copy by
>> constructing the object in the right place.  It also means that having a
>> side effect in the copy constructor (other than something that preserves
>> copy semantics, like reference counting and such) is going to break
>> things.
>
>In all cases where the language (outside of the library) does an
>implicite copy, the object being copied is destructed immediately after,
>before the user can use it for anything else.  So a `copy' that in fact
>`moves' will still work.

Hmmm... I take it that you don't consider pass-by-value to be an
implicit copy? Perhaps you're right, but I don't really see where the
implicit vs. explicit question enters into this. I consider it an axiom
that if you assign "a = b" that you can then assume that "a == b" is
true unless a or b are volatile. If you write a copy constructor or
assignment operator such that this is NOT true, then you are asking for
trouble, IMHO. This leaves me with a delema wrt auto_ptr<> because,
while I like what it is trying to do, I don't like the idea of breaking
fundamental axioms in such a flagrant way. This could cause a ripple
effect. I'm not sure what kinds of compiler optimizations might not be
possible or even if certain semantics might become unpredicatable in
this case. Maybe I'm overstating the problem. Auto_ptr<> semantics seem
simple enough on the face of it and maybe this isn't a problem in
reality. (Programming, especially in C++, is not expected to be the same
as mathmatics, after all.)

-------------------------------------------------------------
Pablo Halpern                   phalpern@truffle.ultranet.com

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ:    http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1996/02/22
Raw View
In article <4gfg21$iga@caesar.ultra.net> phalpern@truffle.ultranet.com
(Pablo Halpern) writes:

|> kanze@gabi.gabi-soft.fr (J. Kanze) wrote:

|> >In article <4eto87$9kf@hermes.synopsys.com> jbuck@Synopsys.COM (Joe
|> >Buck) writes:
|> >> The *language*, not just STL, requires copy constructors that actually
|> >> copy.  The language automatically uses the copy constructor whenever it
|> >> needs to make a copy.  The copy constructor is used to return objects
|> >> from functions and to pass them in by value.  This usaga assumes that
|> >> you get an actual copy.  Copy constructors can be optimized away in
|> >> certain circumstances.  Again, this optimization works based on the
|> >> assumption that a copy constructor does a copy, so you can avoid the
|> >> copy by constructing the object in the right place.  It also means that
|> >> having a side effect in the copy constructor (other than something that
|> >> preserves copy semantics, like reference counting and such) is going to
|> >> break things.

|> >In all cases where the language (outside of the library) does an
|> >implicite copy, the object being copied is destructed immediately after,
|> >before the user can use it for anything else.  So a `copy' that in fact
|> >`moves' will still work.

|> Hmmm... I take it that you don't consider pass-by-value to be an
|> implicit copy? Perhaps you're right, but I don't really see where the
|> implicit vs. explicit question enters into this. I consider it an axiom
|> that if you assign "a = b" that you can then assume that "a == b" is
|> true unless a or b are volatile. If you write a copy constructor or
|> assignment operator such that this is NOT true, then you are asking for
|> trouble, IMHO. This leaves me with a delema wrt auto_ptr<> because,
|> while I like what it is trying to do, I don't like the idea of breaking
|> fundamental axioms in such a flagrant way. This could cause a ripple
|> effect. I'm not sure what kinds of compiler optimizations might not be
|> possible or even if certain semantics might become unpredicatable in
|> this case. Maybe I'm overstating the problem. Auto_ptr<> semantics seem
|> simple enough on the face of it and maybe this isn't a problem in
|> reality. (Programming, especially in C++, is not expected to be the same
|> as mathmatics, after all.)

You're not overstating anything.  You have precisely described the
dilemma concerning auto_ptr, and why there is so much discussion about
it.

In general, I agree with the concerning voiced about the changed
semantics of operator=.  In the case of auto_ptr, however, in all of the
cases where I think one would reasonably want to use it, the value on
the right hand side is either a temporary, or a value about to disappear
anyway.  So the changed semantics don't bother me too much.
--
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
              -- A la recherche d'une activiti dans une region francophone
---
[ To submit articles: try just posting with your news-reader.
                      If that fails, use mailto:std-c++@ncar.ucar.edu
  FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu.
]





Author: kanze@gabi.gabi-soft.fr (J. Kanze)
Date: 1996/02/10
Raw View
In article <4eto87$9kf@hermes.synopsys.com> jbuck@Synopsys.COM (Joe
Buck) writes:

> kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763) writes:
> >In fact, this is a weakness in the STL definition (IMHO).  STL
> >containers require *real* copy constructors, that actually copy.  For
> >something like auto_ptr, this is not reasonable.
>
> The *language*, not just STL, requires copy constructors that actually
> copy.  The language automatically uses the copy constructor whenever it
> needs to make a copy.  The copy constructor is used to return objects from
> functions and to pass them in by value.  This usaga assumes that you get
> an actual copy.  Copy constructors can be optimized away in certain
> circumstances.  Again, this optimization works based on the assumption
> that a copy constructor does a copy, so you can avoid the copy by
> constructing the object in the right place.  It also means that having a
> side effect in the copy constructor (other than something that preserves
> copy semantics, like reference counting and such) is going to break
> things.

In all cases where the language (outside of the library) does an
implicite copy, the object being copied is destructed immediately after,
before the user can use it for anything else.  So a `copy' that in fact
`moves' will still work.

This is also the case in STL when it resizes a vector, for example.

In fact, in the particular example, I don't think that there is a real
problem either.  The user asked for something that the language
(including library) simply doesn't support; he wanted a vector of 10
auto_ptr's all pointing to the same object.  This is a contradiction.
It would be nice if this were made to require a diagnostic, but I don't
see how it would be possible.
--
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
              -- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  Moderation policy:
  http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]





Author: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 1996/02/01
Raw View
In article <01BAEFD6.AD7E8620@dino.int.com> Eugene Lazutkin
<eugene@int.com> writes:

|> Why do I use wrappers?  Just small example: vector< auto_ptr< T > >
|> (or list< auto_ptr< T > >).  I f you tried it, you'd discover that STL
|> (I use ObjectSpace's implementation) uses copy-ctor with a const parameter
|> and auto_ptr doesn't define it.

|> BTW, how come that auto_ptr from Standard C++ Library is incompatible with
|> vector<>, list<> and other STL containers from the same source? Or maybe I
|> have incorrect implementation?

And just when I thought I'd found a solution to the auto_ptr
problem:-).

In fact, this is a weakness in the STL definition (IMHO).  STL
containers require *real* copy constructors, that actually copy.  For
something like auto_ptr, this is not reasonable.  Even supposing that
STL and the language could handle it, what would be the meaning of:

 vector< auto_ptr< T > >
                     v( 10 , auto_ptr< T >( new T ) ) ;

Certainly not what it would seem to be.

A possible solution would be to have two functions everywhere where
the STL requires a fill object.  (The current version has one
function, with a default parameter T() as fill.)  The version without
the fill object parameter would use the default constructor, rather
than copy.  Obviously, this is only interesting if the implementation
only instantiates functions that are actually used.  (I believe that
this is supposed to be the case, although I know that many
implementations do not do this.)

This still leaves a problem with the internal functions, such as
reserve, which may copy the data.  While not a problem for auto_ptr
(since they are copying non-const lvalues), it may be a problem for
other classes.
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
                -- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: doug@monet.ads.com (Doug Morgan)
Date: 1996/02/03
Raw View
In article <9601281244.8175@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:
> ..
> Can someone please remind me why we decided not to allow typedef templates?
> It certainly seems like a bad idea to force everyone to use this silly
> obfuscation for what is obviously a common need.

D&E says: "The extension is technically trivial, but I'm not sure how
wise it would be to introduce yet another renaming feature."

I have no idea why the committee might have killed typedef templates,
but I doubt that any reasoning used had more than the zero technical
merit of the above.

Doug
----------
Doug Morgan         TEL: (408) 744-3510 Booz-Allen & Hamilton
doug@ads.com (UNIX) FAX: (408) 744-3565 385 Moffett Park Drive
morgan_doug@bah.com (MS-Mail)           Suite 110
     Sunnyvale, CA 94089
----------
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: jbuck@Synopsys.COM (Joe Buck)
Date: 1996/02/05
Raw View
kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763) writes:
>In fact, this is a weakness in the STL definition (IMHO).  STL
>containers require *real* copy constructors, that actually copy.  For
>something like auto_ptr, this is not reasonable.

The *language*, not just STL, requires copy constructors that actually
copy.  The language automatically uses the copy constructor whenever it
needs to make a copy.  The copy constructor is used to return objects from
functions and to pass them in by value.  This usaga assumes that you get
an actual copy.  Copy constructors can be optimized away in certain
circumstances.  Again, this optimization works based on the assumption
that a copy constructor does a copy, so you can avoid the copy by
constructing the object in the right place.  It also means that having a
side effect in the copy constructor (other than something that preserves
copy semantics, like reference counting and such) is going to break
things.

Any definition of auto_ptr's copy constructor that doesn't follow these
rules is broken, I'm afraid.  The problem is with auto_ptr, not with
copy constructors or the STL.

--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)

Work for something because it is good,
not just because it stands a chance to succeed.    -- Vaclav Havel
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/01/29
Raw View
esap@cs.tut.fi (Pulkkinen Esa) writes:

>template <class T>
>class type_dereferencer<T*>
>{
>public:
>  typedef T base_type;
>};
[...]
>And if typedef templates were allowed, you could use a slightly better
>syntax:
>
>template <class T>
>typedef type_dereferencer<T>::base_type type_dereference;

Can someone please remind me why we decided not to allow typedef templates?
It certainly seems like a bad idea to force everyone to use this silly
obfuscation for what is obviously a common need.

--
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: Eugene Lazutkin <eugene@int.com>
Date: 1996/01/31
Raw View
On  Monday, January 29, 1996 12:50 PM,  fjh@munta.cs.mu.OZ.AU (Fergus Henderson) wrote:
> esap@cs.tut.fi (Pulkkinen Esa) writes:
>
> >template <class T>
> >class type_dereferencer<T*>
> >{
> >public:
> >  typedef T base_type;
> >};
> [...]
> >And if typedef templates were allowed, you could use a slightly better
> >syntax:
> >
> >template <class T>
> >typedef type_dereferencer<T>::base_type type_dereference;

Don't forget another point: YOU CAN'T INHERIT CONSTRUCTORS.  In fact

1) class B : public A {};

and

2) typedef A B;

is not the same if you have non-default constructors in the class A.
You have to put some constructors in a 1st example, like

class B : public A
{
public:
 B( T1 x ) : A(x) {}
 B( T2 x ) : A(x) {}
 B( T1 x, T2 y ) : A(x,y) {}
 /* ... other constructors ... */
 B() : A() {}
 B( const A& a ) : A(a) {}
};

if you are going to emulate 2nd.  To me the typedef templates would solve
this problem easily and effectifely.

> Can someone please remind me why we decided not to allow typedef templates?

Yeah, why?

> It certainly seems like a bad idea to force everyone to use this silly
> obfuscation for what is obviously a common need.

I wrote several wrappers like written above for my application which uses STL.
When I change the set of possible constructors of the base class I need
find all appropriate wrappers and correct them too.  I have to keep my code
up-to-date manually.

Why do I use wrappers?  Just small example: vector< auto_ptr< T > >
(or list< auto_ptr< T > >).  I f you tried it, you'd discover that STL
(I use ObjectSpace's implementation) uses copy-ctor with a const parameter
and auto_ptr doesn't define it.  The same for a copy-op. Additionally
my VC++ 4.0 tries to instantiate some unused methods (?) and of course doesn't
find less-operator.  That's why I need wrappers.

BTW, how come that auto_ptr from Standard C++ Library is incompatible with
vector<>, list<> and other STL containers from the same source? Or maybe I
have incorrect implementation?

> Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
> fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3

Thanks in advance



Eugene Lazutkin
eugene@int.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: "D. Allan Drummond" <allan.drummond@trilogy.com>
Date: 1996/01/18
Raw View
In writing an STL helper function, I ran into a snag.  The helper function
is used to make a deep copy of a list of pointers, so that the following
code is possible:

#include <list.h>

class A {}

main()
{
    list<A*> alist;
    // Now add bunches of A*'s to the list...

    list<A*> other_alist;
    deep_copy( alist, other_alist );

    // Now modify contents of other_alist with impunity --
    // they're distinct from alist's.
}


Below are the two template functions that do the work.

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

// deep_copy requires that class T have
// a copy constructor, and for best use, one that
// makes a deep copy.

template<class Iter, class ContainedType>
void deep_copy( Iter fromB, Iter fromE, Iter toB, Iter toE, ContainedType* )
{
    while( (fromB != fromE) && (toB != toE) && *fromB )
        *toB++ = new T( **fromB++ );
}

template<class Container>
void deep_copy( Container& from, Container& to )
{
    to = from; // expand to make sure TO is as big as FROM.
               // should be cheap, if this is really a list of pointers.
    Container::value_type type;
    deep_copy( from.begin(), from.end(), to.begin(), to.end(), type );
}

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

Note: STL container classes all have a public typedef like this --

 typedef T value_type;

The above set of functions will always be run on pointer-lists, where
T is a pointer type.

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


So, the obvious strange item is the ContainedType class in the top template
header.  The problem is that Container::value_type is a pointer type, so I
can't say something like *toB = new Container::value_type( **fromB ) --
that would make the rhs a **, which is not the desired *.

The template mechanism has the strange ability to "dereference" types, so
that when I pass a T* to the top function, I can then use the T type
normally.

This seems ugly to me.  How can I get access to the type T (not T*) in the
first function, so that I don't have to pass a bogus parameter to some
second function?


( For the casual reader: You must use all template types in the function
    arguments.  Consider a silly example:

    template<class T, class S> void foo( T t ) { S* s = new S; }

    How could the compiler figure out what S was from the following?

    A a;
    foo( a ); )



I really want to write something like this (the following code is
nonsensical but should convey the spirit of the idea):

template<class Container>
void deep_copy( Container& from, Container& to )
{
    to = from; // expand to make sure TO is as big as FROM.
               // should be cheap, if this is really a list of pointers.
    Container::const_iterator f( from.begin() );
    Container::iterator t( to.begin );

    while( (f != from.end()) && (t != to.end()) && *f )
        *t++ = new (*Container::value_type)( **f++ );
}

It seems as though there's no REAL reason to have to split it into two
functions, but the "type dereferencing" is crucial.

Any suggestions?  Incidentally, the two-function method works great --
feel free to rip it off with impunity.


Thanks,

Allan
allan.drummond@trilogy.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]