Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Jul 29, 2009, 5:24:39 PM (15 years ago)
Author:
rgrieder
Message:

Exception-safety for the Game and Core c'tors as well as load/unload-Graphics.

Location:
code/branches/resource/src/core
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • code/branches/resource/src/core/Core.cc

    r3356 r3363  
    248248
    249249    Core::Core(const std::string& cmdLine)
    250         : bDevRun_(false)
     250        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
     251        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
     252        // Cleanup guard for external console commands that don't belong to an Identifier
     253        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
     254        , bDevRun_(false)
    251255        , bGraphicsLoaded_(false)
     256        , configuration_(new CoreConfiguration()) // Don't yet create config values!
    252257    {
    253258        if (singletonRef_s != 0)
     
    257262        }
    258263        Core::singletonRef_s = this;
    259 
    260         // We need the variables very soon. But don't configure them yet!
    261         this->configuration_ = new CoreConfiguration();
    262264
    263265        // Parse command line arguments first
     
    276278        // create a signal handler (only active for linux)
    277279        // This call is placed as soon as possible, but after the directories are set
    278         this->signalHandler_ = new SignalHandler();
     280        this->signalHandler_.reset(new SignalHandler());
    279281        this->signalHandler_->doCatch(configuration_->executablePath_.string(), Core::getLogPathString() + "orxonox_crash.log");
    280282
     
    295297
    296298        // Manage ini files and set the default settings file (usually orxonox.ini)
    297         this->configFileManager_ = new ConfigFileManager();
     299        this->configFileManager_.reset(new ConfigFileManager());
    298300        this->configFileManager_->setFilename(ConfigFileType::Settings,
    299301            CommandLine::getValue("settingsFile").getString());
    300302
    301303        // Required as well for the config values
    302         this->languageInstance_ = new Language();
     304        this->languageInstance_.reset(new Language());
    303305
    304306        // Do this soon after the ConfigFileManager has been created to open up the
     
    307309
    308310        // Create the lua interface
    309         this->luaBind_ = new LuaBind();
     311        this->luaBind_.reset(new LuaBind());
    310312
    311313        // initialise Tcl
    312         this->tclBind_ = new TclBind(Core::getMediaPathString());
    313         this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());
     314        this->tclBind_.reset(new TclBind(Core::getMediaPathString()));
     315        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
    314316
    315317        // create a shell
    316         this->shell_ = new Shell();
     318        this->shell_.reset(new Shell());
    317319
    318320        // creates the class hierarchy for all classes with factories
     
    321323
    322324    /**
    323         @brief Sets the bool to true to avoid static functions accessing a deleted object.
     325    @brief
     326        All destruction code is handled by scoped_ptrs and SimpleScopeGuards.
    324327    */
    325328    Core::~Core()
    326329    {
    327         delete this->shell_;
    328         delete this->tclThreadManager_;
    329         delete this->tclBind_;
    330         delete this->luaBind_;
    331         delete this->configuration_;
    332         delete this->languageInstance_;
    333         delete this->configFileManager_;
    334 
    335         // Destroy command line arguments
    336         CommandLine::destroyAllArguments();
    337         // Also delete external console commands that don't belong to an Identifier
    338         CommandExecutor::destroyExternalCommands();
    339         // Clean up class hierarchy stuff (identifiers, XMLPort, configValues, consoleCommand)
    340         Identifier::destroyAllIdentifiers();
    341 
    342         delete this->signalHandler_;
    343 
    344330        // Don't assign singletonRef_s with NULL! Recreation is not supported
     331        // The is quite simply because of the pre-main code that uses heap allocation
     332        // And we correctly deallocate these resources in this destructor.
    345333    }
    346334
     
    351339
    352340        // Load OGRE including the render window
    353         this->graphicsManager_ = new GraphicsManager();
     341        scoped_ptr<GraphicsManager> graphicsManager(new GraphicsManager());
    354342
    355343        // The render window width and height are used to set up the mouse movement.
    356344        size_t windowHnd = 0;
    357         Ogre::RenderWindow* renderWindow = GraphicsManager::getInstance().getRenderWindow();
    358         renderWindow->getCustomAttribute("WINDOW", &windowHnd);
     345        graphicsManager->getRenderWindow()->getCustomAttribute("WINDOW", &windowHnd);
    359346
    360347        // Calls the InputManager which sets up the input devices.
    361         inputManager_ = new InputManager(windowHnd);
     348        scoped_ptr<InputManager> inputManager(new InputManager(windowHnd));
    362349
    363350        // load the CEGUI interface
    364         guiManager_ = new GUIManager(renderWindow);
     351        guiManager_.reset(new GUIManager(graphicsManager->getRenderWindow()));
     352
     353        // Dismiss scoped pointers
     354        graphicsManager_.swap(graphicsManager);
     355        inputManager_.swap(inputManager);
    365356
    366357        bGraphicsLoaded_ = true;
     
    372363            return;
    373364
    374         delete this->guiManager_;
    375         delete this->inputManager_;
    376         delete graphicsManager_;
     365        this->guiManager_.reset();;
     366        this->inputManager_.reset();;
     367        this->graphicsManager_.reset();
    377368
    378369        bGraphicsLoaded_ = false;
  • code/branches/resource/src/core/Core.h

    r3349 r3363  
    4343
    4444#include <cassert>
     45#include <boost/scoped_ptr.hpp>
    4546#include "util/OutputHandler.h"
     47#include "util/ScopeGuard.h"
    4648
    4749namespace orxonox
    4850{
    4951    class CoreConfiguration;
     52    using boost::scoped_ptr;
    5053
    5154    /**
     
    5861    class _CoreExport Core
    5962    {
     63        typedef Loki::ScopeGuardImpl0<void (*)()> SimpleScopeGuard;
     64
    6065        public:
    6166            /**
     
    112117            void setThreadAffinity(int limitToCPU);
    113118
    114             // Singletons
    115             ConfigFileManager*    configFileManager_;
    116             Language*             languageInstance_;
    117             LuaBind*              luaBind_;
    118             Shell*                shell_;
    119             SignalHandler*        signalHandler_;
    120             TclBind*              tclBind_;
    121             TclThreadManager*     tclThreadManager_;
     119            // Mind the order for the destruction!
     120            scoped_ptr<SignalHandler>     signalHandler_;
     121            SimpleScopeGuard              identifierDestroyer_;
     122            SimpleScopeGuard              consoleCommandDestroyer_;
     123            scoped_ptr<ConfigFileManager> configFileManager_;
     124            scoped_ptr<Language>          languageInstance_;
     125            scoped_ptr<CoreConfiguration> configuration_;
     126            scoped_ptr<LuaBind>           luaBind_;
     127            scoped_ptr<TclBind>           tclBind_;
     128            scoped_ptr<TclThreadManager>  tclThreadManager_;
     129            scoped_ptr<Shell>             shell_;
    122130            // graphical
    123             InputManager*         inputManager_;        //!< Interface to OIS
    124             GUIManager*           guiManager_;          //!< Interface to GUI
    125             GraphicsManager*      graphicsManager_;     //!< Interface to OGRE
     131            scoped_ptr<GraphicsManager>   graphicsManager_;     //!< Interface to OGRE
     132            scoped_ptr<InputManager>      inputManager_;        //!< Interface to OIS
     133            scoped_ptr<GUIManager>        guiManager_;          //!< Interface to GUI
    126134
    127             bool                  bDevRun_;             //!< True for runs in the build directory (not installed)
    128             bool                  bGraphicsLoaded_;
    129             CoreConfiguration*    configuration_;
     135            bool                          bDevRun_;             //!< True for runs in the build directory (not installed)
     136            bool                          bGraphicsLoaded_;
    130137
    131138            static Core* singletonRef_s;
  • code/branches/resource/src/core/Game.cc

    r3359 r3363  
    4040#include "util/Debug.h"
    4141#include "util/Exception.h"
     42#include "util/ScopeGuard.h"
    4243#include "util/Sleep.h"
    4344#include "util/SubString.h"
     
    133134
    134135        // Set up a basic clock to keep time
    135         this->gameClock_ = new Clock();
     136        this->gameClock_.reset(new Clock());
    136137
    137138        // Create the Core
    138         this->core_ = new Core(cmdLine);
     139        this->core_.reset(new Core(cmdLine));
    139140
    140141        // After the core has been created, we can safely instantiate the GameStates that don't require graphics
     
    153154
    154155        // Do this after the Core creation!
    155         this->configuration_ = new GameConfiguration();
     156        this->configuration_.reset(new GameConfiguration());
    156157    }
    157158
    158159    /**
    159160    @brief
     161        All destruction code is handled by scoped_ptrs and SimpleScopeGuards.
    160162    */
    161163    Game::~Game()
    162164    {
    163         // Destroy the configuration helper class instance
    164         delete this->configuration_;
    165 
    166         // Destroy the GameStates (note that the nodes still point to them, but doesn't matter)
    167         for (std::map<std::string, GameState*>::const_iterator it = constructedStates_.begin();
    168             it != constructedStates_.end(); ++it)
    169             delete it->second;
    170 
    171         // Destroy the Core and with it almost everything
    172         delete this->core_;
    173         delete this->gameClock_;
    174 
    175         // Take care of the GameStateFactories
    176         GameStateFactory::destroyFactories();
    177 
    178165        // Don't assign singletonRef_s with NULL! Recreation is not supported
    179166    }
     
    283270    {
    284271        // Note: The first element is the empty root state, which doesn't need ticking
    285         for (std::vector<GameState*>::const_iterator it = this->loadedStates_.begin() + 1;
     272        for (GameStateVector::const_iterator it = this->loadedStates_.begin() + 1;
    286273            it != this->loadedStates_.end(); ++it)
    287274        {
     
    457444    }
    458445
    459     GameState* Game::getState(const std::string& name)
    460     {
    461         std::map<std::string, GameState*>::const_iterator it = constructedStates_.find(name);
     446    shared_ptr<GameState> Game::getState(const std::string& name)
     447    {
     448        GameStateMap::const_iterator it = constructedStates_.find(name);
    462449        if (it != constructedStates_.end())
    463450            return it->second;
     
    469456            else
    470457                COUT(1) << "Error: Could not find GameState '" << name << "'." << std::endl;
    471             return 0;
     458            return shared_ptr<GameState>();
    472459        }
    473460    }
     
    528515        {
    529516            core_->loadGraphics();
     517            Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics);
    530518            GameMode::bShowsGraphics_s = true;
    531519
     
    536524                if (it->second.bGraphicsMode)
    537525                {
     526                    // Game state loading failure is serious --> don't catch
     527                    shared_ptr<GameState> gameState = GameStateFactory::fabricate(it->second);
    538528                    if (!constructedStates_.insert(std::make_pair(
    539                         it->second.stateName, GameStateFactory::fabricate(it->second))).second)
     529                        it->second.stateName, gameState)).second)
    540530                        assert(false); // GameState was already created!
    541531                }
    542532            }
     533            graphicsUnloader.Dismiss();
    543534        }
    544535    }
     
    549540        {
    550541            // Destroy all the GameStates that require graphics
    551             for (std::map<std::string, GameState*>::iterator it = constructedStates_.begin(); it != constructedStates_.end();)
     542            for (GameStateMap::iterator it = constructedStates_.begin(); it != constructedStates_.end();)
    552543            {
    553544                if (it->second->getInfo().bGraphicsMode)
    554                 {
    555                     delete it->second;
    556545                    constructedStates_.erase(it++);
    557                 }
    558546                else
    559547                    ++it;
     
    577565    {
    578566        this->bChangingState_ = true;
     567        LOKI_ON_BLOCK_EXIT_OBJ(*this, &Game::resetChangingState);
     568
    579569        // If state requires graphics, load it
    580         if (gameStateDeclarations_s[name].bGraphicsMode)
     570        Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics);
     571        if (gameStateDeclarations_s[name].bGraphicsMode && !GameMode::showsGraphics())
    581572            this->loadGraphics();
    582         GameState* state = this->getState(name);
     573        else
     574            graphicsUnloader.Dismiss();
     575
     576        shared_ptr<GameState> state = this->getState(name);
    583577        state->activate();
    584578        if (!this->loadedStates_.empty())
     
    586580        this->loadedStates_.push_back(state);
    587581        state->activity_.topState = true;
    588         this->bChangingState_ = false;
     582
     583        graphicsUnloader.Dismiss();
    589584    }
    590585
    591586    void Game::unloadState(const std::string& name)
    592587    {
    593         GameState* state = this->getState(name);
    594588        this->bChangingState_ = true;
    595         state->activity_.topState = false;
    596         this->loadedStates_.pop_back();
    597         if (!this->loadedStates_.empty())
    598             this->loadedStates_.back()->activity_.topState = true;
    599589        try
    600590        {
     591            shared_ptr<GameState> state = this->getState(name);
     592            state->activity_.topState = false;
     593            this->loadedStates_.pop_back();
     594            if (!this->loadedStates_.empty())
     595                this->loadedStates_.back()->activity_.topState = true;
    601596            state->deactivate();
    602             // Check if graphis is still required
    603             bool graphicsRequired = false;
    604             for (unsigned i = 0; i < loadedStates_.size(); ++i)
    605                 graphicsRequired |= loadedStates_[i]->getInfo().bGraphicsMode;
    606             if (!graphicsRequired)
    607                 this->unloadGraphics();
    608597        }
    609598        catch (const std::exception& ex)
     
    612601            COUT(2) << "         There might be potential resource leaks involved! To avoid this, improve exception-safety." << std::endl;
    613602        }
     603        // Check if graphics is still required
     604        bool graphicsRequired = false;
     605        for (unsigned i = 0; i < loadedStates_.size(); ++i)
     606            graphicsRequired |= loadedStates_[i]->getInfo().bGraphicsMode;
     607        if (!graphicsRequired)
     608            this->unloadGraphics();
    614609        this->bChangingState_ = false;
    615610    }
    616611
    617     std::map<std::string, Game::GameStateFactory*> Game::GameStateFactory::factories_s;
    618 
    619     /*static*/ GameState* Game::GameStateFactory::fabricate(const GameStateInfo& info)
    620     {
    621         std::map<std::string, GameStateFactory*>::const_iterator it = factories_s.find(info.className);
     612    std::map<std::string, shared_ptr<Game::GameStateFactory> > Game::GameStateFactory::factories_s;
     613
     614    /*static*/ shared_ptr<GameState> Game::GameStateFactory::fabricate(const GameStateInfo& info)
     615    {
     616        std::map<std::string, shared_ptr<Game::GameStateFactory> >::const_iterator it = factories_s.find(info.className);
    622617        assert(it != factories_s.end());
    623618        return it->second->fabricateInternal(info);
    624619    }
    625 
    626     /*static*/ void Game::GameStateFactory::destroyFactories()
    627     {
    628         for (std::map<std::string, GameStateFactory*>::const_iterator it = factories_s.begin(); it != factories_s.end(); ++it)
    629             delete it->second;
    630         factories_s.clear();
    631     }
    632620}
  • code/branches/resource/src/core/Game.h

    r3356 r3363  
    4444#include <vector>
    4545#include <boost/shared_ptr.hpp>
     46#include <boost/scoped_ptr.hpp>
    4647#include <boost/preprocessor/cat.hpp>
    4748
     
    5960{
    6061    class GameConfiguration;
     62    using boost::scoped_ptr;
     63    using boost::shared_ptr;
    6164
    6265    //! Helper object required before GameStates are being constructed
     
    7578    class _CoreExport Game
    7679    {
     80        typedef std::vector<shared_ptr<GameState> > GameStateVector;
     81        typedef std::map<std::string, shared_ptr<GameState> > GameStateMap;
    7782        typedef boost::shared_ptr<GameStateTreeNode> GameStateTreeNodePtr;
    7883    public:
     
    8186
    8287        void setStateHierarchy(const std::string& str);
    83         GameState* getState(const std::string& name);
     88        shared_ptr<GameState> getState(const std::string& name);
    8489
    8590        void run();
     
    106111        public:
    107112            virtual ~GameStateFactory() { }
    108             static GameState* fabricate(const GameStateInfo& info);
     113            static shared_ptr<GameState> fabricate(const GameStateInfo& info);
    109114            template <class T>
    110115            static void createFactory(const std::string& className)
    111                 { factories_s[className] = new TemplateGameStateFactory<T>(); }
    112             static void destroyFactories();
     116                { factories_s[className].reset(new TemplateGameStateFactory<T>()); }
    113117        private:
    114             virtual GameState* fabricateInternal(const GameStateInfo& info) = 0;
    115             static std::map<std::string, GameStateFactory*> factories_s;
     118            virtual shared_ptr<GameState> fabricateInternal(const GameStateInfo& info) = 0;
     119            static std::map<std::string, shared_ptr<GameStateFactory> > factories_s;
    116120        };
    117121        template <class T>
     
    119123        {
    120124        public:
    121             GameState* fabricateInternal(const GameStateInfo& info)
    122                 { return new T(info); }
     125            shared_ptr<GameState> fabricateInternal(const GameStateInfo& info)
     126                { return shared_ptr<GameState>(new T(info)); }
    123127        };
    124128
     
    144148        void updateFPSLimiter();
    145149
    146         std::map<std::string, GameState*>  constructedStates_;
    147         std::vector<GameState*>            loadedStates_;
     150        // ScopeGuard helper function
     151        void resetChangingState() { this->bChangingState_ = false; }
     152
     153        scoped_ptr<Clock>                  gameClock_;
     154        scoped_ptr<Core>                   core_;
     155        scoped_ptr<GameConfiguration>      configuration_;
     156
     157        GameStateMap                       constructedStates_;
     158        GameStateVector                    loadedStates_;
    148159        GameStateTreeNodePtr               rootStateNode_;
    149160        GameStateTreeNodePtr               loadedTopStateNode_;
    150         std::vector<GameStateTreeNodePtr > requestedStateNodes_;
    151 
    152         Core*                              core_;
    153         Clock*                             gameClock_;
    154         GameConfiguration*                 configuration_;
     161        std::vector<GameStateTreeNodePtr>  requestedStateNodes_;
    155162
    156163        bool                               bChangingState_;
Note: See TracChangeset for help on using the changeset viewer.