4

假设我有一个std::vector<Obj *> objs(出于性能原因,我的指针不是实际Obj的)。

obj.push_back(new Obj(...));我反复填充它。

完成后,我必须delete推回元素。一种方法是这样做:

for (std::vector<Obj *>::iterator it = objs.begin(); it != objs.end(); ++it) {
    delete *it;
}

但是,如果我可以使用for_each算法来做同样的事情,我很感兴趣:

#include <algorithm>
...
for_each(objs.begin(), objs.end(), delete);

你怎么看?

4

7 回答 7

16

你的问题是这delete不是一个函数,而是一个关键字,因此你不能接受它的地址。

在 C++0x 中,将有一个std::default_delete类(由 使用std::unique_ptr),您可以使用它,或者 - 正如大家所说 - 自己编写一个将是微不足道的(标准的也会引发编译错误,如果您尝试删除不完整的类型)。

#include <vector>
#include <algorithm>
#include <memory>

int main()
{
    std::vector<int*> vec;
    std::for_each(vec.begin(), vec.end(), std::default_delete<int>());
}
于 2010-08-17T17:54:36.303 回答
10

是的,但你需要一个仿函数:

struct delete_ptr
{
    template <typename T>
    void operator()(T* pPtr)
    {
        delete pPtr;
    }
};

std::for_each(objs.begin(), objs.end(), delete_ptr());

在 C++0x 中,lambda 可以帮助您就地制作仿函数:

std::for_each(objs.begin(), objs.end(), [](Obj* pPtr){ delete pPtr; });

然而,面对例外情况,这是危险的。sbi 展示了一个解决方案。

于 2010-08-17T17:50:55.627 回答
4

虽然你可以做到这一点(GMan 已经展示了一个解决方案),但拥有指向拥有资源的裸指针的容器是一种强烈的代码气味。例如,在这段代码中:

  void foo()
  {
    std::vector<Obj *> bar;
    fill(bar);
    use(bar);
    std::for_each(objs.begin(), objs.end(), delete_ptr()); // as GMan suggests
  }

如果use()抛出,您将泄漏对象。

所以最好为此使用智能指针:

std::vector< std::shared_ptr<Obj> > bar;
于 2010-08-17T17:55:41.920 回答
2

不完全是; for_each需要一个可以用 调用的函数或对象,()既不delete是函数也不是对象。您必须将其包装在一个函数(或函数对象)中,可能像:

struct Deleter
{
    void operator()(Obj* obj) {delete obj;}
};

std::for_each(objs.begin(), objs.end(), Deleter());

但是你应该非常小心地使用原始指针来管理对象的生命周期,尤其是在你传递它们的时候。如果您从 中删除它们vector,或者重新分配它们,或者如果您清除vector,或者如果异常、中断或函数返回可能导致向量被破坏,则需要记住删除它们。通常,最好将资源管理和资源使用的职责分开。

最好使用对象向量,除非Obj是多态基类,或者对象确实足够大或足够复杂,以至于复制它们会对性能产生显着影响。如果是这种情况(并且您已经对其进行了分析以确保确实如此),您应该考虑一个智能指针向量(shared_ptr,或者unique_ptr如果您的编译器支持它),或者 Boost 的ptr_vector.

养成使用自动资源管理类的习惯,以后会省去很多麻烦。

于 2010-08-17T18:04:21.073 回答
2

与其尝试解决删除问题,不如通过将shared_ptrs 存储在向量中或使用 boost来使其完全消失ptr_vector(参见http://www.boost.org/doc/libs/1_39_0/libs/ptr_container/doc /tutorial.html )。

于 2010-08-17T18:07:58.303 回答
1

for_each需要一个函数指针或函数对象。对于内存释放,您可以尝试&::operator delete使用释放内存的函数的地址。但是,当您使用 delete 语句时,编译器会在调用之前调用析构函数,operator delete(void*)因此清理实际上不是operator delete(void*)函数的一部分。

使用仿函数 ala GMan 的答案。

于 2010-08-17T17:56:50.103 回答
1

是的。用智能指针填充它并使用 vector.clear() 是最简单的方法。

于 2010-08-17T18:17:54.127 回答