$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: George A. Heintzelman (georgeh_at_[hidden])
Date: 2002-02-03 16:23:11
> From: "Rainer Deyke" <root_at_[hidden]>
> > It sounds like your 'auto_vector' avoids some of the problems of a
> > container of auto_ptrs by conceptually being a container of vanilla
> > pointers.  Unfortunately this has its own set of problems.  Consider:
> > 
> >   auto_vector<Cat> cats;
> >   cats.push_back(new Cat);
> >   cats[0] = new Cat; // Error: memory leak
> 
> With my current version, yes this is unfortunately true.  I know 
> enough not to do that, and so it has never been a problem for me.
> I regard auto_vector as being convenient and not full proof.  
> 
> If more safety is required, I guess we could look at making 
> operator[], front, and back return values rather than references.
> But it would still cause a leak if you did a 
> 
>   *cats.begin() = new Cat;
How about having the interface always dealing with Cats, not pointers 
to Cats? Then the above is a syntax error, as *cats.begin() will be a 
reference to a Cat, not a reference to a pointer to a Cat. You would be 
safe against anything short of:
*cats.begin() = *(new Cat); 
and that I decline to protect programmers from their own stupidity 
for...
My preference is to make the functions which look like vector's act 
like vector's, so all of push_back, etc, pass by value (possibly 
slicing). However, you should supply some other member functions which 
'adopt' a passed-in pointer and place it in an appropriate place, 
avoiding the copy ctor:
cats.adopt_back(new Cat); 
The only issue I see with this interface is that the standard 
push_back, insert, etc, won't behave polymorphically, and this 
container supports polymorphic containment just fine. But since none of 
those functions in STL containers behave that way, this is IMHO not a 
big flaw, as long as functionality is supplied to allow the polymorphic 
behavior when someone desires it. A second potential issue might be that
cats[0] = Calico(...);
would slice, perhaps non-intuitively. Again, I think anyone working 
with polymorphism needs to be aware of slicing possibilities anyway, so 
this is also not a big flaw.
An alternative safe interface would be to have all of the various 
insertion statements (and operator[], which returns a non-const 
reference to an auto_ptr in this scheme) take an auto_ptr instead of a 
straight pointer. This makes the allowed polymorphism a little more 
obvious, and means that accidental adoptions/leaks won't happen. The 
problem as I see it is that begin() now has the semantics of a pointer 
to a pointer to the contained object, which is completely at odds with 
the STL; trying to use algorithms looping over Cats requires 
boost::indirect_iterator when IMHO this should be contained in the 
container's iterators. So while I would probably use this latter 
interface, I prefer the other.
> Or I guess we could go the whole hog and return some sort of 
> proxy that deleted the current pointer on assignment.
> But I don't know if the added safety of either is worth the 
> trouble.  What do others think?  Keep it simple or make it safe?
I think there isn't any proxy necessary in the scheme I would propose. 
The only necessity is to write new iterator types. For that, you can 
use boost::indirect_iterator, though in this case and for orthogonality 
I would rather see it written explicitly. You could I suppose write a 
proxy which prevented (at least simple-minded) slicing possibilities. 
That might be neat, and probably wouldn't be too hard to do, but as I 
say I don't think it is necessary for a useful class, as long as 
functions are provided which do not slice.
George Heintzelman
georgeh_at_[hidden]