Can I call `delete` on a vector of pointers in C++ via for_each <algorithm>?

白昼怎懂夜的黑 提交于 2019-12-19 09:55:16

问题


Suppose I have a std::vector<Obj *> objs (for performance reasons I have pointers not actual Objs).

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?


回答1:


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>());
}



回答2:


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.




回答3:


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;



回答4:


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.




回答5:


Instead of trying to solve the deletion problem, you can make it go away completely by storing shared_ptrs 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).




回答6:


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.




回答7:


Yes. Fill it with smart pointers and use vector.clear() is the easiest way.



来源:https://stackoverflow.com/questions/3505343/can-i-call-delete-on-a-vector-of-pointers-in-c-via-for-each-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!