开发者

Segfaults with singletons

// 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?


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;
}


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜