8

I have a legacy project which has a singleton class like this:

class Singleton
{
public:
    static Singleton& Instance() 
    {
        static Singleton inst;
        return inst;
    }

    void foo();
};

The project uses a DLL which needs to use the same class (part of the source is shared between the hosting application and the DLL, so the DLL has access to Singleton). However, Instance (naturally) returns a different instance for DLL, and a different one for the hosting application. This obviously causes problems.

Is there a way to use the same instance between the DLL and the hosting process? (let's assume that binary compatibility is not an issue.)

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180

3 Answers3

6

One way would be to put an ifdef in your Instance() method so that it behaved differently in your app and dll. For example, have the app one call an exported function on the dll which internally calls the dlls Instance() method. Have the dll version work as originally.

Beware though, unless you make methods like foo() virtual, when the app calls foo() it will call the app's implementation of foo(), and when the dll calls foo() it will call the dll's foo(). This is messy at best and problematic at worst.

The neatest way around this is to make a pure virtual interface which contains the public interface, then have the app get a pointer to this interface class from the dll and use that. This way the app has no code from Singleton and you will save yourself future debug pain.

In a shared header:

struct ISingleton
{
    virtual void foo()=0;
};

DLL_EXPORT ISingleton &GetSingleton();

In Dll:

struct Singleton : public ISingleton
{
    virtual void foo() { /* code */ }
};

ISingleton &GetSingleton()
{
    static Singleton inst;
    return inst;
}

In common code (dll or exe):

GetSingleton().foo();
tul
  • 1,709
  • 16
  • 15
  • Could someone explain why this is/the other answer is not working? Or point me to something that I could read to understand? The main difference I can spot is that, here, there is no static keyword in the header, that there is inheritance, and that more things are in the .cpp. But I don't know if any of that is the relevant difference nor why that would change anything. Maybe I just lack knowledge on when things get stored in the .dll vs. .lib, but I would have expected that all .cpp implementations of an exported class will be stored in the .dll. (I'm on windows, btw) – Warmy Sep 14 '22 at 09:55
4

I've solved the same problem (eg. class used within library, in other library and also in main application) by moving the static Singleton inst; into cpp file.

Foo.h
class Foo{
public:
  static Foo *getInstance();
...

Foo.cpp
Foo *Foo::getInstance(){
  static Foo instance;
  return &foo;
}

The static variable is then in one position inside library (so/dll) and everything runs fine. I'm even able to have different header files for export.

Libor Tomsik
  • 668
  • 7
  • 24
  • this works for me. – zhangxaochen Jun 11 '17 at 18:06
  • 1
    this did NOT work across dll, I had to create a dll entry point, and return a pointer to the instance. – Mia Shani Nov 13 '17 at 20:45
  • 1
    why move to cpp works? – camino Jul 16 '18 at 00:38
  • 2
    @camino It only works if the singleton already belongs to the dll. If the singleton belonged to a static library common to the .exe and the .dll, it wouldn't work. tul answer is much more to the point. You have further answers here https://stackoverflow.com/questions/6935541/c-a-singleton-class-with-dll/6936218#6936218 – Antonio Jan 28 '19 at 23:45
  • Linux: no matter. Win and macOs won't work, singleton has still multiple addresses – Mykola Tetiuk Jul 12 '22 at 04:13
1

The common solution is to have another dll that holds the singleton but not implemented with a static member. See this answer for example.

Community
  • 1
  • 1
Eric Fortin
  • 7,533
  • 2
  • 25
  • 33