Hi,

When I initialise then access the g_spMyLog shared pointer, from within the CSingleton::CreateLog member function, it works ok. Accessing the SP from the static member function of CSingleton::Create() causes an access violation in the original project and an abort in this sample project displayed below.

In the original project I think the object is going out of scope somewhere but I don't know where. The factory function is created within a DLL as return (static_cast<void*>(new CMyLog)); which is then static_cast to a CMylog* straight into a shared_ptr like this: g_spMyLog.reset(static_cast<CMyLog*>(CreateVoidObj(is_Binary))); but that's not included here.

// File: CSingleton.h

#pragma once

#include "CMyLog.h"
#include <string>
#include <boost\shared_ptr.hpp>
#include <boost\make_shared.hpp>

#define BOOSTSP boost::shared_ptr
#define BOOSTMKSHD boost::make_shared

class CSingleton
{
public:
    static void Create(void);
    static void Destroy(void);

    ~CSingleton(void) {}

    BOOSTSP<CMyLog> CreateLog(bool is_Binary);

protected:
    CSingleton(void) {} // Hidden constructor

private:
    // PRIVATE SEMANTICS
    CSingleton(const CSingleton& other) {}                     // Copy constructor
    friend void swap(CSingleton& first, CSingleton& second) {} // Swap implementation
    CSingleton& operator=(CSingleton other) {}                 // Assignment operator
    CSingleton(CSingleton&& other) {}                          // Move constructor
};

extern BOOSTSP<CSingleton> g_spSingleton;
extern BOOSTSP<CMyLog> g_spLog;



// File: CSingleton.cpp

#include "CSingleton.h"
#include "CMyLog.h"

BOOSTSP<CSingleton> g_spSingleton = nullptr;
BOOSTSP<CMyLog> g_spLog = nullptr;
void Create(void);
void Destroy(void);

void CSingleton::Create(void)
{
    if (!g_spSingleton)
    {
        // Create engine and start log
        g_spSingleton.reset(new CSingleton());
        g_spLog = g_spSingleton->CreateLog(false);

        //
        int i = g_spLog->Get(); // << Abort has been called ERROR
        g_spLog->Set(245);    
        i = g_spLog->Get();
    }

} // Create

BOOSTSP<CMyLog> CSingleton::CreateLog(bool is_Binary)
{
    static BOOSTSP<CMyLog> sp; // Ignore this.

    g_spLog = BOOSTSP<CMyLog>(new CMyLog());
    g_spLog->Set(1234); // <== This in the original works (here only)
    int i = g_spLog->Get();

    return sp;
} // CreateLog


void CSingleton::Destroy(void)
{
    g_spSingleton.reset();
    g_spLog.reset();
} // Destroy



// File: CMyLog.h

#pragma once

class CMyLog
{
public:
    CMyLog(void) {}
    ~CMyLog(void) {}

    void Set(int i) { m_i = i; }
    int  Get(void)  { return m_i; }

    int m_i;

private:
    // etc...
};



// File: main.cpp
#include "CSingleton.h"

int main(void)
{
    CSingleton::Create();


    return 0;
}

Muchas gracias to anyone who can help.

Edited 2 Years Ago by Elixir42: typo

Line 73 should be:

return g_spLog;

not

return sp;

because sp is null, and when you return it, and immediately assign it to g_spLog at line 55, you end up with a null pointer in g_spLog.

BTW, despite your efforts, you are still subject to the "static initialization order fiasco" with your code. If you end up calling CSingleton::Create() during some static initialization somewhere, you might enter the Create() function when the g_spSingleton pointer is not yet initialized (and thus, not null, but not valid either). You should use local static variables to solve that problem.

Also, you don't need to initialize shared-pointers to "null", because their default constructor already does that, so, your static variable definitions could just be:

BOOSTSP<CSingleton> g_spSingleton;
BOOSTSP<CMyLog> g_spLog;

and that would be sufficient.

Edited 2 Years Ago by mike_2000_17: typo

Thanks for that Mike. I realise about that first point - I was just testing the global in that funtion. On the other points I have done that. Plus CSingleton::Create only get called once anyhow. Maybe I didn't understand what you meant.

I'm still stuck on why in the sample it works but not in my project. Here are 2 of my original project functions:

Just as above but: g_spEngineLog is g_spLog and g_spGlobalEngine is g_spSingleton

/*************************************************************************
    **  Function    : Create
    **  Description : Manufacture CEngine instance and create engine log.
    **************************************************************************/
    void CEngine::Create(void)
    {
        if (!g_spGlobalEngine)
        {
            // Create engine and start log
            g_spGlobalEngine.reset(new CEngine());
            g_spEngineLog = g_spGlobalEngine->CreateLog(false);

            // Open 
            std::string sLogFilename(nsStringTable::sEngineLogFilename.c_str());

            // For testing purposes
            int i = g_spEngineLog->GetNumber(); // <== ACCESS VIOLATION
            g_spEngineLog->SetNumber(45);
            i = g_spEngineLog->GetNumber();

            // Log info header
            g_spEngineLog->OpenOutput(sLogFilename, std::ios::trunc);
            *g_spEngineLog << "CEngine::Create(): '" << sLogFilename << 
                              "' started on: " << g_spGlobalEngine->GetDate() << 
                              " at: " << g_spGlobalEngine->GetTime() << std::endl;
        }
    } // Create


    /*************************************************************************
    **  Function    : CreateLog
    **  Description : Load the log file ready to be used.
    **************************************************************************/
    BOOSTSP<ISerialization> CEngine::CreateLog(bool is_Binary)
    {
        // Create function pointer
        fpVoidFunctBool CreateVoidObj;

        // Initialise SP with factory function
        boost::shared_ptr<CDLLLoader> spDLL(new CDLLLoader(nsStringTable::sPluginLogDLL.c_str()));

        // Name of factory function
        std::string sFactoryFunction(LPCSTR("CreateClassInstance"));

        // Get the function pointer
        CreateVoidObj = spDLL->GetFunctionPtr<fpVoidFunctBool>(sFactoryFunction);

        // Static class member
        // Call FF and initialise SP with a pointer to the object.
        s_SP.reset(static_cast<ISerialization*>(CreateVoidObj(is_Binary)));

        return s_SP;
    } // CreateLog

How am I getting out of scope...! In the debugger the g_spEngineLog goes red indicating that the contents have changed and it is unable to preview the object. Then crashes when trying to access.

Edited 2 Years Ago by Elixir42: format code

This article has been dead for over six months. Start a new discussion instead.