C++ 我可以在C++;每个单元的via<;算法>;?
假设我有一个C++ 我可以在C++;每个单元的via<;算法>;?,c++,memory,foreach,delete-operator,C++,Memory,Foreach,Delete Operator,假设我有一个std::vector objs(出于性能原因,我的指针不是实际的Objs) 我用obj.push_back(新的obj(…))填充它重复 完成后,我必须删除后推的元素。一种方法是: for (std::vector<Obj *>::iterator it = objs.begin(); it != objs.end(); ++it) { delete *it; } 你觉得怎么样?是的,但你需要一个函子: struct delete_ptr { temp
std::vector objs
(出于性能原因,我的指针不是实际的Obj
s)
我用obj.push_back(新的obj(…))填充它代码>重复
完成后,我必须删除
后推的元素。一种方法是:
for (std::vector<Obj *>::iterator it = objs.begin(); it != objs.end(); ++it) {
delete *it;
}
你觉得怎么样?是的,但你需要一个函子:
struct delete_ptr
{
template <typename T>
void operator()(T* pPtr)
{
delete pPtr;
}
};
std::for_each(objs.begin(), objs.end(), delete_ptr());
然而,面对例外情况,这是危险的 您的问题是删除不是一个函数,而是一个关键字,因此您无法获取它的地址
在C++0x中,将有一个std::default\u delete
类(由std::unique\u ptr
使用),您可以使用该类,或者正如大家所说的那样,自己编写一个类是微不足道的(如果您试图删除不完整的类型,标准类也会引发编译错误)
#包括
#包括
#包括
int main()
{
std::vec;
std::for_each(vec.begin()、vec.end()、std::default_delete());
}
虽然您可以这么做(),但拥有带有指向所拥有资源的裸指针的容器是一种强烈的代码味道。例如,在此代码中:
void foo()
{
std::vector<Obj *> bar;
fill(bar);
use(bar);
std::for_each(objs.begin(), objs.end(), delete_ptr()); // as GMan suggests
}
对于_,每个
都需要一个函数指针或函数对象。对于内存释放,您可以尝试&::operator delete
,它将获取释放内存的函数的地址。但是,当您使用delete语句时,编译器会在调用运算符delete(void*)
之前调用析构函数,因此清除实际上不是运算符delete(void*)
函数的一部分
使用仿函数ala GMan的答案。不完全正确for_每个
都需要一个可以用()
调用的函数或对象,而delete既不是函数也不是对象。您必须将其封装在函数(或函数对象)中,可能类似于:
struct Deleter
{
void operator()(Obj* obj) {delete obj;}
};
std::for_each(objs.begin(), objs.end(), Deleter());
但您应该非常小心地使用原始指针管理对象生命周期,尤其是在传递它们时。如果您从向量中删除它们,或者重新分配它们,或者如果您清除向量,或者如果异常、中断或函数返回可能导致向量被破坏,则需要记住删除它们。一般来说,最好将资源管理和资源使用的责任分开
最好使用对象向量,除非Obj
是一个多态基类,或者对象确实太大或太复杂,复制它们会对性能产生显著影响。如果是这种情况(并且你已经确定了它的情况),那么你应该考虑一个智能指针的矢量(<代码> SydDypPTR<代码>,或者如果你的编译器支持它,代码> UnQuyPPTR <代码>,或者Boost的<代码> pTrvector矢量< /C>
养成使用自动资源管理类的习惯将在将来为您省去很多麻烦。您可以通过将共享的ptr
存储在向量中,或者使用boost的ptr\u向量
(请参阅)来完全消除删除问题。是的。用智能指针填充它并使用vector.clear()是最简单的方法。对于每个_
都不应该修改您正在迭代的集合。@KennyTM:不是,指针值保持不变。(同样,这个要求在C++0x中被取消。)@GMan:我相信你是正确的,但是你有引用(这是我想读的)。@Martin:当然,§25.2.4/2:“效果:将f应用于从first开始到last-1范围内的每个迭代器的解引用结果。[注:如果first类型满足可变迭代器的要求,f可以通过解引用迭代器应用非恒定函数。-结束注]“注是重要部分。所有答案都很好,谢谢大家!我赢了。”) 但我喜欢你的格式,让我们形成一个循环依赖关系。@GMan:Garrghh!你让我陷入了一个循环。Grrr。我很想知道为什么这被否决了。有什么问题吗?@sbi:在你发布答案之前,我已经把你的答案放在我的答案里了。所以我“赢得了[比赛]”.但我更喜欢你的,所以我把它们循环在一起。@GMan:哦,我甚至都没见过。循环是一件邪恶的事情。(就像谷歌搜索“递归”。)格曼先生,你能解释一下functor的用法吗?特别是,为什么普通的delete
不起作用?谢谢。@bodacydo:delete
在语言层面上不起作用的原因是它是一个关键字,你不能将关键字传递到函数中。你不能用delete
调用它,就像用catch调用它一样de>或static\u cast
(函数需要传递变量。函子和函数指针就是这样。)啊,我正要问为什么没有人演示如何使用lambda来实现这一点,这时我发现我错过了你的。:)
非常有见地,谢谢。我从来没有想过自己会使用&::操作符delete
。(我也知道它不会调用我对象的析构函数)。@bodacydo:你说得对,这不会调用析构函数。这只能用于释放原始内存块,而不能用于删除对象。我想操作符+
(我相信可以与std::foreach()
一起使用)then不是一个关键字,而是一个函数的名称,它的名称恰好由一个关键字和一个运算符组成?@sbi:那会是什么样子?据我所知,如果你想使用operator+
,那么你需要的函数对象叫做std::plus
(是的,operatorX
是一个函数,除了内置类型。)@UncleBens:你是说我们不能获取一个恰好是运算符的函数的地址吗?@sbi:你可以这样做:&some\u type::operator+
,是的。@sbi:我的意思是当你做类似于std::foreach(a,b,static\u cast)(&operator)的事情时
#include <vector>
#include <algorithm>
#include <memory>
int main()
{
std::vector<int*> vec;
std::for_each(vec.begin(), vec.end(), std::default_delete<int>());
}
void foo()
{
std::vector<Obj *> bar;
fill(bar);
use(bar);
std::for_each(objs.begin(), objs.end(), delete_ptr()); // as GMan suggests
}
std::vector< std::shared_ptr<Obj> > bar;
struct Deleter
{
void operator()(Obj* obj) {delete obj;}
};
std::for_each(objs.begin(), objs.end(), Deleter());