Make object deletion safe while iterating through their list

Perhaps a bit of a hack but there is no other way to implement this now
master
Piotr Dziwinski 2015-07-12 13:16:07 +02:00
parent 4dc40a8853
commit a1e5812740
2 changed files with 39 additions and 26 deletions

View File

@ -44,6 +44,7 @@ CObjectManager::CObjectManager(Gfx::CEngine* engine,
Gfx::CParticle* particle) Gfx::CParticle* particle)
: m_objectFactory(new CObjectFactory(engine, terrain, oldModelManager, modelManager, particle)) : m_objectFactory(new CObjectFactory(engine, terrain, oldModelManager, modelManager, particle))
, m_nextId(0) , m_nextId(0)
, m_shouldCleanRemovedObjects(false)
{ {
} }
@ -55,9 +56,6 @@ bool CObjectManager::DeleteObject(CObject* instance)
{ {
assert(instance != nullptr); assert(instance != nullptr);
if (m_objectsIteratingUserCount > 0)
throw std::logic_error("Trying to delete object while holding iterators to objects map!");
// TODO: temporarily... // TODO: temporarily...
auto oldObj = dynamic_cast<COldObject*>(instance); auto oldObj = dynamic_cast<COldObject*>(instance);
if (oldObj != nullptr) if (oldObj != nullptr)
@ -66,13 +64,26 @@ bool CObjectManager::DeleteObject(CObject* instance)
auto it = m_objects.find(instance->GetID()); auto it = m_objects.find(instance->GetID());
if (it != m_objects.end()) if (it != m_objects.end())
{ {
m_objects.erase(it); it->second.reset();
m_shouldCleanRemovedObjects = true;
return true; return true;
} }
return false; return false;
} }
void CObjectManager::CleanRemovedObjects()
{
auto it = m_objects.begin();
if (it != m_objects.end())
{
if (it->second == nullptr)
it = m_objects.erase(it);
}
m_shouldCleanRemovedObjects = false;
}
void CObjectManager::DeleteAllObjects() void CObjectManager::DeleteAllObjects()
{ {
for (auto& it : m_objects) for (auto& it : m_objects)

View File

@ -66,28 +66,33 @@ class CObjectIteratorProxy
public: public:
inline CObject* operator*() inline CObject* operator*()
{ {
return m_it->second.get(); return m_currentIt->second.get();
} }
inline void operator++() inline void operator++()
{ {
++m_it; do
{
++m_currentIt;
} while (m_currentIt != m_endIt && m_currentIt->second == nullptr);
} }
inline bool operator!=(const CObjectIteratorProxy& other) inline bool operator!=(const CObjectIteratorProxy& other)
{ {
return m_it != other.m_it; return m_currentIt != other.m_currentIt;
} }
private: private:
friend class CObjectContainerProxy; friend class CObjectContainerProxy;
CObjectIteratorProxy(CObjectMapCIt it) CObjectIteratorProxy(CObjectMapCIt currentIt, CObjectMapCIt endIt)
: m_it(it) : m_currentIt(currentIt)
, m_endIt(endIt)
{} {}
private: private:
CObjectMapCIt m_it; CObjectMapCIt m_currentIt;
CObjectMapCIt m_endIt;
}; };
class CObjectContainerProxy class CObjectContainerProxy
@ -95,31 +100,22 @@ class CObjectContainerProxy
private: private:
friend class CObjectManager; friend class CObjectManager;
inline CObjectContainerProxy(const CObjectMap& map, int& userCount) inline CObjectContainerProxy(const CObjectMap& map)
: m_map(map) : m_map(map)
, m_mapUserCount(userCount) {}
{
m_mapUserCount++;
}
public: public:
inline ~CObjectContainerProxy()
{
m_mapUserCount--;
}
inline CObjectIteratorProxy begin() const inline CObjectIteratorProxy begin() const
{ {
return CObjectIteratorProxy(m_map.begin()); return CObjectIteratorProxy(m_map.begin(), m_map.end());
} }
inline CObjectIteratorProxy end() const inline CObjectIteratorProxy end() const
{ {
return CObjectIteratorProxy(m_map.end()); return CObjectIteratorProxy(m_map.end(), m_map.end());
} }
private: private:
const CObjectMap& m_map; const CObjectMap& m_map;
int& m_mapUserCount;
}; };
/** /**
@ -172,7 +168,10 @@ public:
//! Returns all objects //! Returns all objects
inline CObjectContainerProxy GetAllObjects() inline CObjectContainerProxy GetAllObjects()
{ {
return CObjectContainerProxy(m_objects, m_objectsIteratingUserCount); if (m_shouldCleanRemovedObjects)
CleanRemovedObjects();
return CObjectContainerProxy(m_objects);
} }
//! Finds an object, like radar() in CBot //! Finds an object, like radar() in CBot
@ -240,9 +239,12 @@ public:
bool cbotTypes = false); bool cbotTypes = false);
//@} //@}
protected: private:
void CleanRemovedObjects();
private:
CObjectMap m_objects; CObjectMap m_objects;
int m_objectsIteratingUserCount;
std::unique_ptr<CObjectFactory> m_objectFactory; std::unique_ptr<CObjectFactory> m_objectFactory;
int m_nextId; int m_nextId;
bool m_shouldCleanRemovedObjects;
}; };