Search code examples
c++dllstatic-librariesstatic-membersdllexport

Using static members across Static Lib and DLL - member value is resetting


I have a solution set up with 3 projects:

  • Lib1 (A static library)
  • Dll1 (A dynamic library)
  • App1 (A Blank Windows Store application, could be any application type)

Lib1 contains the following:

Export.h

#pragma once

#ifdef DLL_EXPORT
    #define EXPORT __declspec(dllexport)
#else
    #define EXPORT __declspec(dllimport)
#endif

Lib1.h

#pragma once
#include "Export.h"

class Member { };

class EXPORT Base {
public:
    static Member* GetStaticMember();
    virtual void SetMember(Member* member) = 0;

protected:
    static Member* m_member;
};

class Worker {
public:
    void DoSomething();
};

Lib1.cpp

#include "pch.h"
#include "Lib1.h"

Member* Base::m_member;

Member* Base::GetStaticMember() {
    return m_member;
}

void Worker::DoSomething() {
    Member* test = Base::GetStaticMember(); // RETURNS 0
}

Dll1 contains the following

Dll1.h

#pragma once
#include "Lib1.h"
#include "Export.h"

class EXPORT ChildA : public Base {
public:
    virtual void SetMember(Member* member) override;
};

Dll1.cpp

#include "pch.h"
#include "Dll1.h"

void ChildA::SetMember(Member* member) {
    Base::m_member = member;

    Member* test = Base::GetStaticMember(); // RETURNS CORRECT ADDRESS
}

App1 contains the following

Member* member = new Member();
ChildA* childa = new ChildA();
childa->SetMember(member); // Base::GetStaticMember() inside this RETURNS CORRECT ADDRESS

Worker* worker = new Worker();
worker->DoSomething(); // Base::GetStaticMember() inside this RETURNS 0

The Problem

When stepping through in the debugger, Base::GetStaticMember() returns the correct address to the member after it is set (but still while inside childa->SetMember(). Once OUTSIDE childa, Base::GetStaticMember() returns 0 instead. When inside worker->DoSomething(), Base::GetStaticMember() is also returning 0. Can anyone explain to me what the cause of this is and how to fix it so that accessing Base::GetStaticMember() either outside or inside methods of the Dll or Lib will return the correct address and not 0?


Solution

  • If you're using a static lib linked to multiple DLL's and/or your EXE, each will get its own static member variable. Think of the mechanics of how the *link phase of each of these happens and you'll see why.

    You can turn your static vars into pointers referencing shared memory backed by a memory mapped file, but I warn you it gets tricky to manage. I've done it by maintaining a temp memory-map-file using the name of the class+member+pid as the mapping name (note: the pid was to allow multiple processes to run without stomping on each others shared mem). it worked surprisingly well.