Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland asked on

Templatized singleton gets created twice!

Ah hello.

I have come across a serious problem regarding a singleton class I have in a DLL.  To put it short, I am finding that I get two instances of the same singleton created only lines apart in my code.  This is baffling.

Please see the class diagram VS has created for at http://img242.imageshack.us/img242/3425/classdiagrammz6.jpg.

I have a test app that calls the following:

BOOL CMyTestTestDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      MyNamespace::CSessionManager<MyNamespace::CEngine1>& instance = MyNamespace::CSessionManager<MyNamespace::CEngine1>::Instance();

      instance.Initialise(_T("eg"));
      instance.RunFunc ();

      return TRUE;
}

Now, this results in RunFunc() being called:

BOOL RunFunc ()
{
      CSessionManager<CEngine1>& instance = CSessionManager<CEngine1>::Instance();
      return ExecuteSynchronousTask ( );
}

You can see I obtain a second instance at this point, just to make sure it is the same one as was initialised in my dialog test app.  It is, since its m_bInitialised member is TRUE.  

We then get

BOOL CBaseEngine::ExecuteSynchronousTask ()
{
      CSessionManager<CEngine1>& i2 = CSessionManager<CEngine1>::Instance();

      return TRUE;
}

This is where things go wrong.  i2 insists on creating a second object, not using the one that has already been created.  This is causing major inconsistency (in reality, the objects are far more complicated than is shown).

Someone please tell me what is going on here and how I can correct it.  It is crucial that I can access the same object that was initialised in my test app from within my DLL.  It cannot be a DLL-boundary issue since the call to MyFunc() is executed within the DLL, and that works fine.

I have created a very simple project (<100 lines) to demonstrate this problem; please download it at http://download.yousendit.com/AFD129DF0DD259D2 (vS 2008 format).

TIA
C++

Avatar of undefined
Last Comment
evilrix

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
evilrix

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
SOLUTION
rstaveley

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
evilrix

>> I'd expect that each will get its own instantiation of that object
BTW: I meant instantiated class template instance not class object instance.
rstaveley

It is the *class* that is getting instantiated in both the DLL and in the calling code.

Because of that you get two instances of:

      static CSessionManager<CEngine1>& Instance()
      {
            static CSessionManager<CEngine1> instance;
            return instance;
      }

That means you get two instances of 'instance'.
rstaveley

:-) evilrix was ahead of me twice
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
ASKER
mrwad99

Thanks.

Excellent.  That makes sense.  But if it is the case, how come

BOOL RunFunc ()
{
      CSessionManager<CEngine1>& instance = CSessionManager<CEngine1>::Instance();
      return ExecuteSynchronousTask ( );
}

the instance object created there is not a new one?  It is the same as the one I instantiated in my test app.  Only when ExecuteSynchronousTask () gets called do I get a new object created.

?
ASKER
mrwad99

Ignore that.  I just stepped into the code and found out that MyFunc() is executed in the context of the app.

evilrix

>> Ignore that.  I just stepped into the code and found out that MyFunc() is executed in the context of the app.

:)
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
mrwad99

OK then.  I still have a problem.

I need to ensure that I get hold of the same singleton object within the DLL and the test app.

Does anyone have any ideas how to do this?

I am currently looking at another class that does the managing, but this might be too convoluted.

TIA
evilrix

I'm afraid the ins and outs of Windows DLLs are not my bag (being as I am not really a Windows programmer) so beyond suggesting the possible reason I'm afraid any suggestion for a solution I offer would be conjecture. Sorry.
ASKER
mrwad99

OK Rx, I understand.  However, if you can comment on the below, please do.  Otherwise, rstaveley, please let me know your opinion or any better way you can see.

OK.  I have come up with the following, located in SessionManager.h, which is part of the DLL.

// In .h
template<class BurningEnginePolicy>
class CGetInstance
{
public:
      static CSessionManager<BurningEnginePolicy>& GetInstance() { return GetInstanceImpl(); }
protected:
      static DLL_SPEC CSessionManager<BurningEnginePolicy>& GetInstanceImpl();
};

// in .cpp

namespace MyNamespace
{

template<>
CSessionManager<CEngine1>& CGetInstance<CEngine1>::GetInstanceImpl()
{
      return CSessionManager<CEngine1>::Instance();
}

template<>
CSessionManager<CEngine2>& CGetInstance<CEngine2>::GetInstanceImpl()
{
      return CSessionManager<CEngine2>::Instance();
}

}      // namespace MyNamespace

My test app and the DLL both now use

MyNamespace::CSessionManager<MyNamespace::CEngine1>& instance = MyNamespace::CGetInstance<MyNamespace::CEngine1>::GetInstance();

and they end up with the same object.

Any comments on this?
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
evilrix

>> Any comments on this?
At this time no... I'd need to investigate this myself further and being as I'm currently at work I'm not in a position to do this now. If I get time I'll try and reproduce the problem myself tonight at home.

-Rx.
SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
rstaveley

Apologies if this is "suck eggs"... but in case it isn't....

Do be careful to ensure that your session manager does not create/destroy any objects destroyed/created by the calling code, because they have separate heaps. If your session manager acts as a class factory, you'll need to make sure than any objects created by the manager are deleted by the manager.

e.g.

    // Session manager code referenced - it lives in the DLL
    CSessionManager& sessionManager = GetSessionManagerFromYourDll();

    // Let's say the session manager creates a CSession object from the DLL's free store
    CSession* pSession = sessionManager.createSession();

    // Let's say that the calling code deletes the object
    delete session; // Kaboom - deleted from the wrong heap manager

Your session manager will need to delete the CSession object

    // Let's say the session manager creates a CSession object from the DLL's free store
    CSession* pSession = sessionManager.createSession();

    // Get the sessionManager to delete the object
    // The correct heap manager will be used
    sessionManager.deleteSession(session);

DLLs are tricky.
evilrix

>> If I get time I'll try and reproduce the problem myself tonight at home
I think rstaveley has said all that needs saying, I doubt there is anything useful I can add.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
mrwad99

Thanks very much both.  evilrix, no offence, but you did state that rstaveley was ahead of you twice, hence rstaveley gets all the points.
evilrix

>> evilrix, no offence, but you did state that rstaveley was ahead of you twice
Um, actually that was rstaveley stating that about me! Please look again at {http:#21623097} The very first post I made identified the problem.
rstaveley

mrwad99, if you could award evilrix that would be splendid. He knows where I live and we are fiercely competitive in these parts ;-)
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
evilrix

>> if you could award evilrix that would be splendid.
Actually, may I be so bold as to suggest a split since I think we both contributed.

This identified the problem: {http:#21623015} -- I'd suggest 40%
This clarified the problem: {http:#21623088} -- I'd suggest 30%
This provided more info: {http:#21624357} -- I'd suggest 30%

So, the final points allocation, if my maths are correct, would be a 60/40 split in favour of rstaveley.

Any objections?

>> He knows where I live and we are fiercely competitive in these parts
Muhahaha, you know it :)
ASKER
mrwad99

Oh dear.  Someone has been looking at a monitor for too long...

evilrix: please accept my appologies.  I have requested in community support for this to be re-opened (http:Q_23441195.html) so I can properly assign points in the fashion you mention above.
evilrix

^^^ I also believe that to be the best possible selection for the PAQ database.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
evilrix

>> please accept my appologies
No worries, no harm done :)

>> I have requested in community support for this to be re-opened
Many thanks. I think the recommendation I've made above {http:#21668591} is fair, but you are obviously free to do as you see fit.

Cheers.

-Rx.
ASKER
mrwad99

Right, sorted :o)
evilrix

Thanks mrwad99.
Cheers rstaveley.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes