diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 8a3d0a1e5..6197eed42 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -146,6 +146,8 @@ CArtHandler::CArtHandler() CArtHandler::~CArtHandler() { + BOOST_FOREACH(CArtifact * art, artifacts) + delete art; } std::vector CArtHandler::loadLegacyData(size_t dataSize) diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 29ebd5440..75797ade0 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -1002,6 +1002,8 @@ int CCreatureHandler::stringToNumber(std::string & s) CCreatureHandler::~CCreatureHandler() { + BOOST_FOREACH(auto & creature, creatures) + creature.dellNull(); } CreatureID CCreatureHandler::pickRandomMonster(const boost::function &randGen, int tier) const diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index d5966f7aa..9c92ab592 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -161,7 +161,7 @@ public: void addToSlot(SlotID slot, CreatureID cre, TQuantity count, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature void addToSlot(SlotID slot, CStackInstance *stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature - void clear() OVERRIDE; + void clear() override; void setFormation(bool tight); CArmedInstance *castToArmyObj(); @@ -177,7 +177,7 @@ public: void eraseStack(SlotID slot); //slot must be occupied void joinStack(SlotID slot, CStackInstance * stack); //adds new stack to the existing stack of the same type void changeStackCount(SlotID slot, TQuantity toAdd); //stack must exist! - bool setCreature (SlotID slot, CreatureID type, TQuantity quantity) OVERRIDE; //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack + bool setCreature (SlotID slot, CreatureID type, TQuantity quantity) override; //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack void setToArmy(CSimpleArmy &src); //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all. const CStackInstance& getStack(SlotID slot) const; //stack must exist diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 680b9b0aa..6d6435c5a 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -763,6 +763,9 @@ CGameState::~CGameState() //delete initialOpts; delete applierGs; delete objCaller; + + BOOST_FOREACH(auto ptr, hpool.heroesPool) // clean hero pool + ptr.second.dellNull(); } BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town) diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index bd656e2ef..4e37aa875 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -255,6 +255,17 @@ CObjectHandler::CObjectHandler() logGlobal->traceStream() << "\t\tDone loading banks configs"; } +CObjectHandler::~CObjectHandler() +{ + BOOST_FOREACH(auto & mapEntry, banksInfo) + { + BOOST_FOREACH(auto & vecEntry, mapEntry.second) + { + vecEntry.dellNull(); + } + } +} + int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj) { switch (obj->ID) //find appriopriate key @@ -817,6 +828,8 @@ void CGHeroInstance::initHero() commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders commander->giveStackExp (exp); //after our exp is set } + else + commander = nullptr; hoverName = VLC->generaltexth->allTexts[15]; boost::algorithm::replace_first(hoverName,"%s",name); @@ -904,12 +917,14 @@ void CGHeroInstance::initHeroDefInfo() } CGHeroInstance::~CGHeroInstance() { + commander.dellNull(); } bool CGHeroInstance::needsLastStack() const { return true; } + void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const { if(h == this) return; //exclude potential self-visiting diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index 85570c215..97480aafc 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -1404,6 +1404,7 @@ public: std::vector resVals; //default values of resources in gold CObjectHandler(); + ~CObjectHandler(); int bankObjToIndex (const CGObjectInstance * obj); diff --git a/lib/CSpellHandler.cpp b/lib/CSpellHandler.cpp index 0be2dee39..958a66154 100644 --- a/lib/CSpellHandler.cpp +++ b/lib/CSpellHandler.cpp @@ -131,6 +131,15 @@ CSpell::CSpell() isOffensive = false; } +CSpell::~CSpell() +{ + for (size_t i=0; i CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const { std::vector ret; @@ -479,7 +488,7 @@ CSpellHandler::CSpellHandler() auto v = v_node.convertTo >(); auto a = a_node.convertTo >(); - for (int i=0; i<4 ; i++) + for (int i=0; ieffects.size() ; i++) { Bonus * b = JsonUtils::parseBonus(bonus_node); b->sid = s->id; //for all @@ -493,10 +502,8 @@ CSpellHandler::CSpellHandler() s->effects[i].push_back(b); } - } - auto find_in_map = [](std::string name, std::vector &vec) { auto it = bonusNameMap.find(name); @@ -533,6 +540,14 @@ CSpellHandler::CSpellHandler() } } +CSpellHandler::~CSpellHandler() +{ + BOOST_FOREACH(auto & spell, spells) + { + spell.dellNull(); + } +} + std::vector CSpellHandler::getDefaultAllowed() const { std::vector allowedSpells; diff --git a/lib/CSpellHandler.h b/lib/CSpellHandler.h index 189cd9e3d..8d5e639de 100644 --- a/lib/CSpellHandler.h +++ b/lib/CSpellHandler.h @@ -46,6 +46,7 @@ public: std::vector counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs) CSpell(); + ~CSpell(); std::vector rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret) si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none) @@ -96,7 +97,7 @@ private: ETargetType targetType; - std::vector effects [4]; + std::vector > effects; // [level 0-3][list of effects] std::vector immunities; //any of these grants immunity std::vector limiters; //all of them are required to be affected @@ -166,6 +167,7 @@ class DLL_LINKAGE CSpellHandler public: CSpellHandler(); + ~CSpellHandler(); std::vector< ConstTransitivePtr > spells; /** diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index 69f019ab9..136d28658 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -73,11 +73,11 @@ CTown::CTown() CTown::~CTown() { - BOOST_FOREACH(auto build, buildings) + BOOST_FOREACH(auto & build, buildings) build.second.dellNull(); - BOOST_FOREACH(CStructure * str, clientInfo.structures) - delete str; + BOOST_FOREACH(auto & str, clientInfo.structures) + str.dellNull(); } CTownHandler::CTownHandler() @@ -85,6 +85,12 @@ CTownHandler::CTownHandler() VLC->townh = this; } +CTownHandler::~CTownHandler() +{ + BOOST_FOREACH(auto faction, factions) + faction.dellNull(); +} + JsonNode readBuilding(CLegacyConfigParser & parser) { JsonNode ret; diff --git a/lib/CTownHandler.h b/lib/CTownHandler.h index 539f44cf6..46d7261cc 100644 --- a/lib/CTownHandler.h +++ b/lib/CTownHandler.h @@ -225,6 +225,7 @@ public: std::vector > factions; CTownHandler(); //c-tor, set pointer in VLC to this + ~CTownHandler(); std::vector loadLegacyData(size_t dataSize) override; diff --git a/lib/filesystem/CResourceLoader.cpp b/lib/filesystem/CResourceLoader.cpp index c2029c848..d268f37ff 100644 --- a/lib/filesystem/CResourceLoader.cpp +++ b/lib/filesystem/CResourceLoader.cpp @@ -193,6 +193,12 @@ CResourceLoader * CResourceHandler::get() } } +void CResourceHandler::clear() +{ + delete resourceLoader; + delete initialLoader; +} + //void CResourceLoaderFactory::setInstance(CResourceLoader * resourceLoader) //{ // CResourceLoaderFactory::resourceLoader = resourceLoader; diff --git a/lib/filesystem/CResourceLoader.h b/lib/filesystem/CResourceLoader.h index 4fd29241b..c2458a4a0 100644 --- a/lib/filesystem/CResourceLoader.h +++ b/lib/filesystem/CResourceLoader.h @@ -375,6 +375,13 @@ public: */ static void initialize(); + /** + * Semi-debug method to track all possible cases of memory leaks + * Used before exiting application + * + */ + static void clear(); + /** * Will load all filesystem data from Json data at this path (config/filesystem.json) * @param prefix - prefix for all paths in filesystem config diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 933534661..e1edcd320 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -30,6 +30,7 @@ #include "../lib/GameConstants.h" #include "../lib/logging/CBasicLogConfigurator.h" #include "../lib/CConfigHandler.h" +#include "../lib/ScopeGuard.h" #include "../lib/UnlockGuard.h" @@ -315,6 +316,7 @@ CVCMIServer::~CVCMIServer() { //delete io; //delete acceptor; + /delete firstConnection; } CGameHandler * CVCMIServer::initGhFromHostingConnection(CConnection &c) @@ -351,8 +353,13 @@ void CVCMIServer::newGame() assert(clients == 1); //multi goes now by newPregame, TODO: custom lobbies CGameHandler *gh = initGhFromHostingConnection(c); + + auto onExit = vstd::makeScopeGuard([&]() + { + vstd::clear_pointer(gh); + }); + gh->run(false); - vstd::clear_pointer(gh); } void CVCMIServer::newPregame() @@ -544,6 +551,8 @@ int main(int argc, char** argv) //and return non-zero status so client can detect error throw; } + //delete VLC; //can't be re-enabled due to access to already freed memory in bonus system + CResourceHandler::clear(); return 0; }