Search code examples
c++constructorreferenceinitializationdllexport

Anything wrong with this design to initialize the array in the DLL?


Lets assume we've got a DLL and there should be an array stored globally in it that's going to be exported, the thing is we want to initialize it by reading some content from a file, so personally I find myself no other way than putting it in a struct to be able to initialize using constructor:

struct Construction{
 public:
  Construction(){
   //do the initialization thing and read the needed data from the file
  }
  SomeType sTArray[100];
};

__declspec(dllexport) Construction obj();

Now where it's going to be used, the programmer can initialize a reference to it and then use the reference like below:

SomeType (&arrayRef)[100]=obj.sTArray;

Now would you think I'm wrong in any context?


Solution

  • Yes, you've set yourself up for a very nasty surprise at some point.

    1. Global object constructors run during the startup of the C runtime for the DLL.
    2. The C runtime startup code runs during DLLMain.
    3. During DLLMain, you are holding the DLL loader lock.
    4. Your object constructor may involve calls to Win32 api's that load other system DLL's.
    5. Tring to load another DLL while already holding the DLL loader lock results in a swift death for your process.

    I'd recommend that you hold off on initializing the array until the first attempt to access it, which will require that you expose the array indirectly as the result of a function call:

    struct Construction{
    public:
      Construction() : bInit(false) {};
      SomeType* GetArray()
      {
        if(!bInit)
        {
          //do the initialization thing and read the needed data from the file
          bInit = true;
        }
        return sTArray;
      };
    private:
      SomeType sTArray[100];
      bool bInit;
    };
    
    __declspec(dllexport) Construction obj();
    

    Of course, this would need to be split into separate header and implementation files.