Search code examples
c++dllstaticsingletonraii

How to solve a problem in using RAII code and non-RAII code together in C++?


We have 3 different libraries, each developed by a different developer, and each was (presumably) well designed. But since some of the libraries are using RAII and some don't, and some of the libraries are loaded dynamically, and the others aren't - it doesn't work.

Each of the developers is saying that what he is doing is right, and making a methodology change just for this case (e.g. creating a RAII singleton in B) would solve the problem, but will look just as an ugly patch.

How would you recommend to solve this problem?

Please see the code to understand the problem:


My code:

static A* Singleton::GetA()
{
    static A* pA = NULL;
    if (pA == NULL)
    {
        pA = CreateA();
    }
    return pA;
}

Singleton::~Singleton()  // <-- static object's destructor, 
                         // executed at the unloading of My Dll.
{
     if (pA != NULL)
     {
         DestroyA();
         pA = NULL;
     }
}

"A" code (in another Dll, linked statically to my Dll) :

A* CreateA()
{
    // Load B Dll library dynamically
    // do all other initializations and return A*
}
void DestroyA()
{
    DestroyB();
}

"B" code (in another Dll, loaded dynamically from A) :

static SomeIfc* pSomeIfc;
void DestroyB()
{
    if (pSomeIfc != NULL)
    {
        delete pSomeIfc;  // <-- crashes because the Dll B was unloaded already,
                          // since it was loaded dynamically, so it is unloaded
                          // before the static Dlls are unloaded.
        pSomeIfc = NULL;
    }
}

Solution

  • At first this looks like a problem of dueling APIs, but really it's just another static destructor problem.

    Generally it's best to avoid doing anything nontrivial from a global or static destructor, for the reason you've discovered but also for other reasons.

    In particular: On Windows, destructors for global and static objects in DLLs are called under special circumstances, and there are restrictions on what they may do.

    If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors and destructors and any code that is called from them.

    http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx

    The restrictions are explained on that page, but not very well. I would just try to avoid the issue, perhaps by mimicking A's API (with its explicit create and destroy functions) instead of using a singleton.