views:

125

answers:

3

Hello, I have such code:

// Non singleton
class MyLogManager
{
  void write(message) {Ogre::LogManager::getSingletonPtr()->logMessage(message);}
}

class Utils : public singleton<Utils>
{
   MyLogManager *handle;
   MyLogManager& getHandle { return *handle; }
};

namespace someNamespace
{
   MyLogManager &Log() { return Utils::get_mutable_instance().getHandle(); }
}

int main()
{
   someNamespace::Log().write("Starting game initializating...");
}

In this code I'm using boost's singleton (from serialization) and calling Ogre's log manager (it's singleton-type too).

The program fails at any trying to do something with Ogre::LogManager::getSingletonPtr() object with code

User program stopped by signal (SIGSEGV)

I checked that getSingletonPtr() returns address 0x000

But using code Utils::get_mutable_instance().getHandle().write("foo") works good in another part of program. What's wrong could be there with calling singletons?


Real version of Utils class:

class Utils : public singleton<Utils>
{
    protected:
        ConfigManager *configHandlePtr;
        LogManager *logHandlePtr;

    public:
        Utils()
        {
            configHandlePtr = new ConfigManager();

            string engineLog = configHandle().getValue<string>("engine.logFilename", "Engine.log");
            logHandlePtr = new LogManager(engineLog);
        }
        ~Utils()
        {
            delete configHandlePtr;
            delete logHandlePtr;
        }

        ConfigManager &configHandle() const { return *configHandlePtr; }
        LogManager &logHandle() const { return *logHandlePtr; }
};

And here is the real code of LogManager class:

class LogManager
{
    protected:
        string mDefaultPath;

    public:
        LogManager(const string &logPath = "Engine.log") :
                mDefaultPath(logPath) { }

        void write(const string &message, const string logFile = "")
        {
            string workPath = mDefaultPath;


            Ogre::LogManager *logHandle = Ogre::LogManager::getSingletonPtr(); // [logHandle=0x000]
            Ogre::Log *log2Handle = logHandle->getLog(workPath); // [SEGFAULT]
            log2Handle->logMessage(message);

            Ogre::LogManager::getSingletonPtr()->logMessage(message);
        }
};

UPDATE:

I have a static library (there is my engine code) and the main own programm which links static this library. When I call my config handle (which doesn't use Ogre) everything is okay! There is also resourceManager, it uses Ogre too. And it fails like logManager. Both this managers uses Ogre's singleton. Maybe it's impossible to call it from another library?

A: 

I don't know Boost's singleton, but I notice some strange things in your 'Utils' class.

First of all, getHandle returns a reference to handle, but handle is a local variable that goes out of scope if you leave the method, so the reference to it will also be invalid.

Second, you didn't initialize handle in the getHandle method.

Patrick
There was typing error, sory. I return `*handle`. And I specially didn't write **getHandle** initialization to make the code cleaner.
Ockonal
A: 

Are you sure your Ogre LogManager is correctly initialized?

Or maybe with your libraries you have one instance of the singleton in each library and only the one in your main program is correctly initialized?

In this case you have to declare the singletons in your libraries as "extern" but I'm not sure it applies to statically linked libraries.

Nikko
Yeah, it works great in another part of code. Look, please, at update.
Ockonal
+1  A: 

It feels like you have typical "static initialization order fiasco" - your Utils instance created before one (or both) of other singletons.

Try change Utils::configHandle() to something like this:

ConfigManager &configHandle() const {
    static std::auto_ptr<ConfigManager> configHandlePtr(0);
    if (!configHandlePtr.get()) {
       configHandlePtr.reset(new ConfigManager());
       // init configHandlePtr like you want
    }
    return *configHandlePtr;
}
Sergey