正确删除std::列表中分配给其他地方的指针
Correctly delete pointers in std::list allocated elsewhere
可能重复:
std::list::remove方法是否调用每个被移除元素的析构函数?
我有一个SpriteHandler类,它允许用户注册指向Sprite对象的指针以进行绘制,它所做的只是访问对象上的方法。我想写一个安全捕获,如果用户在程序结束时忘记删除与指针相关的内存,它会自动删除(用户也不用担心!(:
//SpriteHandler.h
class SpriteHandler {
public:
//...
void RegisterObject(Sprite* object);
bool IsRegistered(Sprite* object);
void UnregisterObject(Sprite* object);
private:
//...
static std::list<Sprite*>* _sprite = NULL;
};
//SpriteHandler.cpp
std::list<Sprite*>* SpriteHandler::_sprites = NULL;
void SpriteHandler::RegisterObject(Sprite* object) {
if(object == NULL) return;
if(_sprites == NULL) _sprites = new std::list<Sprite*>();
_sprites->push_back(object);
_sprites->sort(UDLessSprite);
}
bool SpriteHandler::IsRegistered(Sprite* object) {
return std::binary_search(_sprites->begin(), _sprites->end(), object);
}
void SpriteHandler::UnregisterObject(Sprite* object) {
if(object == NULL) return;
if(IsRegistered(object) == false) return;
_sprites->remove(object);
if(_sprites->size() <= 0) {
if(_sprites) {
_sprites->clear();
delete _sprites;
_sprites = NULL;
}
return;
}
_sprites->sort(UDLessSprite);
}
void SpriteHandler::Release() {
if(_sprites) {
std::list<Sprite*>::iterator _iter = _sprites->begin();
while(_iter != _sprites->end()) {
delete (*_iter);
(*_iter) = NULL;
++_iter;
}
_sprites->clear();
delete _sprites;
_sprites = NULL;
}
}
我遇到的问题是,在第一个指针被删除后,下一个迭代器指向一个已经释放的对象(内存位置是0xfeeefeee(
如何正确地遍历它们,删除每一个
如果您想要安全和隐式资源清理,请不要使用原始指针,使用smart-pointers!
STL容器的问题是:
如果包含的对象是指针,STL容器请勿拥有销毁它的所有权。您必须在每个包含的指针上显式调用delete来删除它所指向的内容。
看看这个类似的问题这里。
最好的方法不是将原始指针存储在STL容器中,而是使用它们的智能表亲智能指针(boost::shared_ptr
(查看Boost文档,这些指针表亲足够智能,可以在没有人引用它们时自行解除分配,并为您省去现在面临的问题。
这段代码有很多错误。但它们都源于这条线:
std::list<Sprite*>* _sprite = NULL;
除非您使用C++0x,否则这不会编译。不能像这样设置非静态成员的值。除非您希望它是静态的,否则您应该使用static
关键字。
但更糟糕的是,您正在堆上分配一个std::list
。为什么?在需要的时候分配一个,然后在析构函数中解除分配。只需将其设为常规成员变量即可。
C++是而不是Java。并不是所有的东西都必须是指针。
如果您要声明这些Sprite
对象的所有权,则需要实际声明它们的所有权。这最好用某种智能指针来完成。至少,您应该有一个std::list<std::auto_ptr<Sprite> >
。这将确保在从列表中删除条目时删除Sprite
对象。如果您有权访问Boost(如果没有,则需要访问它(,则可以使用boost::shared_ptr
。C++0x提供了与std::shared_ptr
相同的功能。
std::auto_ptr
只允许一个对象拥有指针,而boost::shared_ptr
允许共享所有权(因此得名(。这对您的代码来说是不必要的(至少从我们可以看到的情况来看(,但允许Sprite
对象的共享所有权并不是一个坏主意。在C++0x中,应该使用std::unique_ptr
而不是std::auto_ptr
。
无论哪种方式,您的代码现在看起来都是这样的:
//SpriteHandler.h
class SpriteHandler {
public:
//...
void RegisterObject(Sprite* object);
bool IsRegistered(Sprite* object);
void UnregisterObject(Sprite* object);
private:
//...
std::list<boost::shared_ptr<Sprite> > _sprite;
};
void SpriteHandler::RegisterObject(Sprite* object) {
if(!object) return;
_sprites.push_back(object);
_sprites.sort(UDLessSprite);
}
bool SpriteHandler::IsRegistered(Sprite* object) {
return std::binary_search(_sprites.begin(), _sprites.end(), object);
}
struct SpriteTester{
SpriteTester(Sprite *testValue) : _testValue(testValue) {}
bool operator()(const boost::shared_ptr<Sprite> &other) const{
return other.get() == _testValue;
}
Sprite *_testValue;
};
void SpriteHandler::UnregisterObject(Sprite* object) {
if(object == NULL) return;
_sprites.remove_if(object, SpriteTester(object));
//Deleting an entry cannot make the list unsorted.
}
void SpriteHandler::Release() {
_sprites.clear();
}
请注意,我引入了SpriteTexture。这是因为现在我们使用智能指针,所以不能将Sprite*
传递给std::list::remove
。如果这样做,它将把它包装在boost::shared_ptr
临时文件中,从而导致指针被删除。这很糟糕,所以我不得不使用自定义测试仪。
此外,如果您想让Sprite
对象注册到类中,那么Sprite
对象构造函数(或工厂方法(应该进行注册。用户应该无法创建未注册的Sprite
s。
- 结构和双指针隐藏在其他结构中,多层混淆
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 包含指向其他结构的指针向量的结构
- 我可以使用 decltype() 或其他东西通过指针获取真实类型吗?
- 在指针中对其他信息进行编码
- char* 除了作为C++中的指针之外,还有其他功能吗?
- C++ 指向其他类函数的指针函数
- 当动态库中的指针仍被其他库使用时,如何删除该指针
- 指向用随机指针归档的其他类对象的指针的c++向量
- 为什么可以将所有类型转换为其他指针类型?
- 常量字符 * 与其他指针不同
- C++ 减少使用指针、原始指针或其他指针和/或返回可为空的非指针
- 单例、shared_ptr、原始指针或其他指针
- 将指针设置为 nullptr 是否会影响指向同一地址的其他指针
- C++ 多态函数以 void * 和其他指针类型为参数:是否被认为是模棱两可的
- 我可以将nullptr强制转换为其他指针类型吗
- 将浮点数*或其他指针转换为无符号字符*
- 检查指针在其他指针中删除对象后是否为 NULL
- 从基类型到其他指针的转换
- 创建指向其他指针的指针数组