Can I call `delete` on a vector of pointers in C++ via for_each <algorithm>?
Suppose I have a std::vector<Obj *> objs
(for performance reasons I have pointers not actual Obj
s).
I populate it with obj.push_back开发者_高级运维(new Obj(...));
repeatedly.
After I am done, I have to delete
the pushed-back elements. One way is to do this:
for (std::vector<Obj *>::iterator it = objs.begin(); it != objs.end(); ++it) {
delete *it;
}
However, I am interested if I can use for_each
algorithm to do the same:
#include <algorithm>
...
for_each(objs.begin(), objs.end(), delete);
What do you think?
Your problem is that delete
is not a function, but rather a keyword and as such you can't take it's address.
In C++0x, there will be a std::default_delete
class (used by std::unique_ptr
), which you could use, or - as everyone's saying - writing one yourself would be trivial (the standard one also raises a compile error, if you try to delete an incomplete type).
#include <vector>
#include <algorithm>
#include <memory>
int main()
{
std::vector<int*> vec;
std::for_each(vec.begin(), vec.end(), std::default_delete<int>());
}
Yes, but you need a functor:
struct delete_ptr
{
template <typename T>
void operator()(T* pPtr)
{
delete pPtr;
}
};
std::for_each(objs.begin(), objs.end(), delete_ptr());
In C++0x, lambda's help you make functors in-place:
std::for_each(objs.begin(), objs.end(), [](Obj* pPtr){ delete pPtr; });
However, this is dangerous, in the face of exceptions. sbi has shown a solution.
While you can do this (GMan has shown a solution), having containers with naked pointers to owned resources is a strong code smell. For example, in this code:
void foo()
{
std::vector<Obj *> bar;
fill(bar);
use(bar);
std::for_each(objs.begin(), objs.end(), delete_ptr()); // as GMan suggests
}
if use()
throws, you'll leak objects.
So it's better to use smart pointers for this:
std::vector< std::shared_ptr<Obj> > bar;
Not exactly; for_each
requires a function or object that can be invoked with ()
, and delete
is neither a function nor an object. You will have to wrap it up in a function (or function object), perhaps like:
struct Deleter
{
void operator()(Obj* obj) {delete obj;}
};
std::for_each(objs.begin(), objs.end(), Deleter());
But you should be very careful managing object lifetimes with raw pointers, especially if you're passing them around. You'll need to remember to delete them if you erase them from the vector
, or reassign them, or if you clear the vector
, or if an exception, break or function return might cause the vector to be destroyed. In general, it's always better to separate the responsibilities of resource management and resource usage.
You'd be better off with a vector of objects, unless Obj
is a polymorphic base class, or the objects really are big or complicated enough that copying them will have a noticeable impact on performance. If that is the case (and you've profiled it to be sure that it's the case), you should consider a vector of smart pointers (shared_ptr
, or unique_ptr
if your compiler supports it), or Boost's ptr_vector
.
Getting in the habit of using automatic resource management classes will save you a lot of headaches in the future.
Instead of trying to solve the deletion problem, you can make it go away completely by storing shared_ptr
s in the vector, or by using boost's ptr_vector
(see http://www.boost.org/doc/libs/1_39_0/libs/ptr_container/doc/tutorial.html).
for_each
needs a function pointer or function object. For memory deallocation you could try &::operator delete
, which would take the address of the function that deallocates memory. However, when you use the delete statement the compiler calls the destructor before calling operator delete(void*)
so cleanup is actually not part of the operator delete(void*)
function.
Use a functor ala GMan's answer.
Yes. Fill it with smart pointers and use vector.clear() is the easiest way.
精彩评论