Re: auto_ptr vs. boost shared_ptr
Carl Barron wrote:
James Kanze <kanze.james@neuf.fr> wrote:
vector< shared_ptr< int > > v1; // OK.
vector< auto_ptr< int > > v2; // Undefined Behavior, but probably a
compile error.
True, but most of the time, I find that raw pointers are
best here. Of course, I usually use the Boehm collector, so
I don't need a surrogate for garbage collection.
Does your GC handle things like
struct larger_than_10
{
bool operator () (int *p) {return *p > 10;}
};
struct create_ptr()
{
int i;
create_ptr():i(1){};
int * operator () () {return new int(i++);}
};
struct kill
{
void operator () (int *x) {delete x;}
};
int main()
{
std::vector<int *> data;
std::generate_n(std::back_inserter(data),1000,create_ptr());
std::vector<int *>::iterator last =
std::remove_if
(
data.begin(),
data.end(),
larger_than_10()
);
std::for_each(last,data.end(),kill());
data.erase(last,data.end());
}
remove_if blindly overwrites the int *'s so the deleted ones are either
never deleted until the os takes over, or are deleted mutliple times.
That's not the problem here. The collector recovers the memory
whenever there's no active pointer to it, so there's no problem
in that respect. (Obviously, you don't need the for_each with
kill.)
There can be a problem in that data.erase() doesn't actually
free memory. It calls the "destructor" on the freed elements,
and a destructor on a pointer is a no-op. The results are that
the memory corresponding to any pointers between last and
data.end() will not be freed until the vector itself is
destroyed.
To date, this has not been a problem in my code; my vectors tend
to grow, and never shrink. But it's not hard to imagine cases
were it could be a problem. Somewhere on my to do list are the
modifications in the g++ implementation of the standard library
to ensure that pointers in conceptually raw memory are
effectively nulled.
fine of the int *'s are not on the heap but statically
allocated but it is a pitfall someone that does not examine
the actual code of remove_if will not think of.
There's no real pitfall with regards to remove_if. With garbage
collection, you replace the 'kill' with nulling the pointer, and
everything works fine. Ideally, however, you don't want to have
to do this (and in some cases, it may not even be practical).
Conceptually, it's fairly straightforward to say that the raw
memory in a container is null'ed. Practically, the major
difficult is in understanding someone else's code, to find the
correct locations.
// For is a forward iterator.
template <class For,class Pred>
For remove_if(For begin,For end, Rred pred)
{
For last(begin);
while(begin != end)
{
if(!pred(*begin))
{
*last = *begin;
++last;
}
++begin;
}
return last;
}
looks like a reference implementation to me of remove_if. If
your GC handles overwrites like this,
I've never seen a garbage collector which didn't.
its ok, but using raw ptrs in any stl container is a recipe
for disaster,
That's far too global a statement. Even without garbage
collection, I often have containers with raw pointers.
if the access to the container is not controlled, and kept
away from the 'user'.
From which user? If my class has internal invariants which
concern an STL container that it uses, obviously this container
is "kept away from the user"---the user of my class. And in
fact, the STL is far to low-level to expose at the class
interface level, usually. When speaking about the STL, I would
say that the 'user' is my class. (There are special cases, and
at least two of my classes explicitely expose std::vector's.
One through a const reference, and the other by replicating the
parts of the std::vector interface which don't modify the
topology.)
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]