 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Mike Gibson Guest
|
Posted: Wed Oct 20, 2004 4:24 pm Post subject: Standard way to delete container of pointers |
|
|
As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
This doesn't seem to actually call the destructor for A. Is there
some problem with the way that I am using the ptr_fun adaptor? The
only way that I have found to solve this problem is create a wrapper
functor that does the same thing and use that as the parameter to
for_each:
template <class T>
struct delete_ptr : std::unary_function<T*, void>
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr<A>());
Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
Mike Gibson
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Mang Guest
|
Posted: Thu Oct 21, 2004 4:00 pm Post subject: Re: Standard way to delete container of pointers |
|
|
"Mike Gibson" <megibson (AT) gmail (DOT) com> schrieb im Newsbeitrag
news:c71602db.0410190901.56c7106b (AT) posting (DOT) google.com...
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end,ptr_fun&operator
delete));
|
This line contains various syntax errors, but I think I can guess what
you
want to do.
It's a big No, No.
::operator delete only frees memory. It does not call any destructors.
| Quote: |
This doesn't seem to actually call the destructor for A. Is there
some problem with the way that I am using the ptr_fun adaptor?
|
You use the wrong function to be called.
The
| Quote: | only way that I have found to solve this problem is create a wrapper
functor that does the same thing and use that as the parameter to
for_each:
template
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end,delete_ptrA
|
More correct than your previous try, but still wrong (besides the
obvious
syntax errors).
std::vector requires its instantiation type to be copyable. At all
times.
When you call delete p, then the pointer remaining in the vector is not
copyable any more.
The solution to this problem would be to pass the pointer per reference
and
set it to 0 after the call to delete.
However, there is left the problem with exception safety. So you go on
to:
| Quote: |
Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
|
Yes. It's called shared_ptr. You instantiate your container with this
smart
pointer, and not with dumb pointers.
Alternatively, you can look for libraries that contain smart containers
invented for exactly this reason (to manage pointers to heap-objects).
Google will help you.
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Thu Oct 21, 2004 4:14 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Mike Gibson wrote:
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
|
Presumably, each element of my_vector was individually allocated with
"new A" and nobody else is using or deleting these. Frankly, the
proper way would NOT be tossing around pointers that need to be managede
seperately, but to wrap the dynamic allocation of A inside some other
class that would manage it (perhaps a boost shared_ptr).
| Quote: |
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
|
Despite it's unfortunate name, "operator delete" is NOT the
implementation
of the delete operator, it's the memory deallcoator. Not only does the
above not call the destructors, it isn't even necesarily the way to
deallocate the memory (perhaps A used some other allocation function).
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Thu Oct 21, 2004 4:44 pm Post subject: Re: Standard way to delete container of pointers |
|
|
"Mike Gibson" <megibson (AT) gmail (DOT) com> wrote
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
|
My advoce is that what you're are doing is going to be considerable
harder
than you think. For example, all member functions must be made
exception-safe
to
prevent all leaks.
| Quote: | Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
|
We just had a review of my Smart Container Library...it probably does
what you
want.
You can download the review version from
http://groups.yahoo.com/group/boost/files/pointer%20container/
smart_container.zip
Feedback is welcome
br
Thorsten
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Thu Oct 21, 2004 5:10 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Mike Gibson wrote:
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
This doesn't seem to actually call the destructor for A. Is there
some problem with the way that I am using the ptr_fun adaptor?
|
The behaviour you experience is correct. "operator delete" simply frees
the storage and it's not supposed to invoke the destructor. It's the
delete-expression, i.e.: "delete p", that first invokes the destructor
and subsequently calls operator delete.
| Quote: | The
only way that I have found to solve this problem is create a wrapper
functor that does the same thing and use that as the parameter to
for_each:
template <class T
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
|
That's what I would write. Some people suggested that it should be more
correct to write:
template <class T>
struct delete_ptr : std::unary_function<T*, void>
{
void operator() (T*& p) const
{
delete p;
p = 0;
}
};
That's because leaving invalid pointers into a container may trigger
undefined behaviour on certain implementations, even if the cointer is
going to be destroyed right away. Personally, I never worked on an
implementation where that would really make a difference.
| Quote: |
Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
|
In Boost there is a functional boost::checked_deleter<T> that does
exactly what your delete_ptr<T> does, plus a safety-check that the type
is actually complete (deleting an incomplete type may trigger undefined
behaviour).
HTH,
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ulrich Eckhardt Guest
|
Posted: Thu Oct 21, 2004 5:39 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Mike Gibson wrote:
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
|
Don't! Use a vector of smart pointers instead.
| Quote: | Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
This doesn't seem to actually call the destructor for A. Is there
some problem with the way that I am using the ptr_fun adaptor?
|
No, the problem is that '::operator delete' is only responsible for
releasing memory, it is NOT the same as invoking delete on a pointer.
| Quote: | The only way that I have found to solve this problem is create a
wrapper functor that does the same thing and use that as the parameter
to for_each:
template <class T
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
Is there a more standard way of doing this?
|
I don't think so.
| Quote: | Perhaps even in something semi-standard such as Boost?
|
Boost has something called checked_delete(r), which is basically the same as
your delete_ptr<> but it additionally assures that T is a complete type(you
don't want to call delete on a pointer to an incomplete type).
Uli
--
FAQ: http://parashift.com/c++-faq-lite/
/* bittersweet C++ */
default: break;
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Thu Oct 21, 2004 5:40 pm Post subject: Re: Standard way to delete container of pointers |
|
|
[email]megibson (AT) gmail (DOT) com[/email] (Mike Gibson) wrote in message
news:<c71602db.0410190901.56c7106b (AT) posting (DOT) google.com>...
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated so I do a for_each over all the pointers and delete each one
with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
This doesn't seem to actually call the destructor for A.
|
Normal. You're calling the deallocation function. There is no function
for the operator delete.
| Quote: | Is there some problem with the way that I am using the ptr_fun
adaptor? The only way that I have found to solve this problem is
create a wrapper functor that does the same thing and use that as the
parameter to for_each:
template <class T
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
Is there a more standard way of doing this?
|
Only what you're doing. Except that technically, what you're doing is
undefined behavior. It's formally illegal for a container to hold a
delete pointer, so you have to do something like:
void operator()( T*& p )
{
T* tmp = NULL ;
std::swap( tmp, p ) ;
delete tmp ;
}
In practice, I wouldn't worry about it.
| Quote: | Perhaps even in something semi-standard such as Boost?
|
Not that I know of, although there is boost::bind.
--
James Kanze GABI Software http://www.gabi-soft.fr
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! ]
|
|
| Back to top |
|
 |
Didier Trosset Guest
|
Posted: Thu Oct 21, 2004 7:39 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Mike Gibson wrote:
--- 8< ---
| Quote: | template
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
|
I've been adviced a nicer version:
struct delete_ptr
{
template <class P>
void operator() (P p)
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr());
Note that you don't have to specify the type of the objects you want to
delete anymore.
Didier
| Quote: | Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
Mike Gibson
|
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ralf Fassel Guest
|
Posted: Thu Oct 21, 2004 7:41 pm Post subject: Re: Standard way to delete container of pointers |
|
|
* [email]megibson (AT) gmail (DOT) com[/email] (Mike Gibson)
| Quote: | Now, after using this vector, I need to destroy all the memory I
have allocated
|
If you'd put smart pointers in the vector, the pointers would handle
the deletion for you when they're destroyed by the vectors DTOR.
Other than that, why not
while (!myvector.empty()) {
delete myvector.back();
myvector.pop_back();
}
Has the advantage of not leaving dangling pointers in the vector (ok,
the vector will cease to exist right after this, but...)
R'
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Fri Oct 22, 2004 12:09 am Post subject: Re: Standard way to delete container of pointers |
|
|
[email]megibson (AT) gmail (DOT) com[/email] (Mike Gibson) writes:
| Quote: | As is commonly done, I have created a container of pointers to objects
of class A:
std::vector<A*> my_vector;
Now, after using this vector, I need to destroy all the memory I have
allocated
|
Actually, you have to destruct the objects pointed to by my_vector's
elements. Deallocating the memory they occupy is only part of the story.
| Quote: | so I do a for_each over all the pointers and delete each
one with:
std::for_each(my_vector.begin(), my_vector.end(), ptr_fun(&::operator
delete));
|
This causes ::operator delete() to invoked for each of my_vector's elements.
::operator delete() is a mere deallocation function.
| Quote: | This doesn't seem to actually call the destructor for A.
|
This is the consequence.
| Quote: | Is there some problem with the way that I am using the ptr_fun adaptor?
|
No. The problem is with the approach.
| Quote: | The
only way that I have found to solve this problem is create a wrapper
functor that does the same thing and use that as the parameter to
for_each:
template <class T
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
Is there a more standard way of doing this? Perhaps even in something
semi-standard such as Boost?
|
Change the value type of my_vector:
std::vector< boost::shared_ptr my_vector;
This makes my_vector's elements the true owners of "their" A object.
The A objects they point to will be reliably destructed, e.g. when
- my_vector itself is destructed
- my_vector.clear() is called
- elements are erased from my_vector
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Daniel Aarno Guest
|
Posted: Fri Oct 22, 2004 5:42 pm Post subject: Re: Standard way to delete container of pointers |
|
|
| Quote: | The
only way that I have found to solve this problem is create a wrapper
functor that does the same thing and use that as the parameter to
for_each:
template <class T
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
|
I use two extremely usefull templates for most of my memory deallocation
needs.
Firs there is the element delter which is basically the same as the above
except that it also zeros the pointer (on demand or always for debugging)
which
can be of great help because using a 0 pointer gives segfault and not strange
behaviour.
template<typename T, bool zero=false>
class ElemDeleter {
public:
void operator()(T* &o) {
delete o;
#ifdef NDEBUG
if(zero)
#endif
o = 0;
}
};
Following the same line of thought I usually also have a
delete-and-set-to-NULL
function that I use for deletion of "normal" pointers.
template<typename T>
inline void DelNZero(T* &o) { delete o; o = NULL; }
Just don't forget that if you are working with arrays you need special
functions for them to use the correct delete[] operator.
Here I also assume the compiler is smart enough to optimize the if(false) away
for template argument (since it is known at compiletime) so the zeroing in
ElemDeleter is not any overhead if you don't use it.
Anyone care to comment on this, any insight if this is good or bad practice,
any issues I havn't thought of?
/Daniel Aarno
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Catalin Pitis Guest
|
Posted: Fri Oct 22, 2004 5:44 pm Post subject: Re: Standard way to delete container of pointers |
|
|
"Didier Trosset" <didier-dot-trosset (AT) acqiris (DOT) com> wrote
| Quote: | Mike Gibson wrote:
--- 8< ---
template
struct delete_ptr : std::unary_function
{
void operator() (T* p) const
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr
I've been adviced a nicer version:
struct delete_ptr
{
template <class P
void operator() (P p)
{
delete p;
}
};
std::for_each(my_vector.begin(), my_vector.end(), delete_ptr());
Note that you don't have to specify the type of the objects you want to
delete anymore.
|
Why not a shorter version:
template
void delete_pointer( T* p)
{
delete p;
}
for_each( my_vector.begin(), my_vector.end(), delete_pointer);
Catalin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
jnorberg@gmail.com Guest
|
Posted: Sat Oct 23, 2004 2:24 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Thomas Mang wrote:
| Quote: | std::vector requires its instantiation type to be copyable. At all
times.
When you call delete p, then the pointer remaining in the vector is
not
copyable any more.
|
Correct me if I'm wrong, but a pointer is copyable no matter what it
points to. The container never dereference the pointer.
__
Jonas Norberg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Frank Birbacher Guest
|
Posted: Sun Oct 24, 2004 2:47 pm Post subject: Re: Standard way to delete container of pointers |
|
|
Hi!
[email]jnorberg (AT) gmail (DOT) com[/email] wrote:
| Quote: | Correct me if I'm wrong, but a pointer is copyable no matter what it
points to. The container never dereference the pointer.
|
No, you are wrong. Copying a pointer which does not point to a
valid object and which does not point one-past-the-end of an
array invokes undefined behaviour by the standard.
Frank
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Peter Dimov Guest
|
Posted: Sun Oct 24, 2004 2:47 pm Post subject: Re: Standard way to delete container of pointers |
|
|
[email]jnorberg (AT) gmail (DOT) com[/email] wrote in message news:<1098436356.256077.274750 (AT) f14g2000cwb (DOT) googlegroups.com>...
| Quote: | Thomas Mang wrote:
std::vector requires its instantiation type to be copyable. At all
times.
When you call delete p, then the pointer remaining in the vector is
not
copyable any more.
Correct me if I'm wrong, but a pointer is copyable no matter what it
points to. The container never dereference the pointer.
|
3.7.3.2/4: "If the argument given to a deallocation function in the
standard library is a pointer that is not the null pointer value
(4.10), the deallocation function shall deallocate the storage
referenced by the pointer, rendering invalid all pointers referring to
any part of the deallocated storage. The effect of using an invalid
pointer value (including passing it to a deallocation function) is
undefined."
Whether "using" here refers to dereference or to lvalue to rvalue
conversion is an interesting, although a bit academic, question. But
see:
http://groups.google.com/groups?selm=hnsngr-ya023180000306000631030001%40news.pacbell.net
for an example of an architecture that uses (used?) the stricter
meaning.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|