1

假设我们有一个 DLL,并且应该有一个全局存储在其中的数组将被导出,问题是我们想通过从文件中读取一些内容来初始化它,所以我个人发现自己没有别的办法,只能放它在一个结构中能够使用构造函数进行初始化:

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

__declspec(dllexport) Construction obj();

现在要在哪里使用它,程序员可以初始化对它的引用,然后使用如下引用:

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

现在你会认为我在任何情况下都错了吗?

4

2 回答 2

5

是的,你在某个时候为自己准备了一个非常令人讨厌的惊喜。

  1. 全局对象构造函数在 DLL 的 C 运行时启动期间运行。
  2. C 运行时启动代码在 DLLMain 期间运行。
  3. 在 DLLMain 期间,您持有 DLL 加载程序锁。
  4. 您的对象构造函数可能涉及对加载其他系统 DLL 的 Win32 api 的调用。
  5. 尝试在已经持有 DLL 加载程序锁的情况下加载另一个 DLL 会导致您的进程迅速死亡。

我建议您推迟初始化数组,直到第一次尝试访问它,这将要求您作为函数调用的结果间接公开数组:

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();

当然,这需要分成单独的头文件和实现文件。

于 2010-11-30T15:44:15.720 回答
3

由于 DLL 中的 CRT 和可执行文件中的 CRT 可能不同,因此您应该提供Construction一个release删除已分配对象的方法。这样,您将保证从适当的 CRT 调用释放函数。您还需要Construction通过指针返回以排除复制操作。以下代码说明了如何实现它的方法:

// DLL export header
struct IConstruction {
protected:
  virtual ~IConstruction() {}
public:
  virtual void release() =0;
  virtual SomeType& get_array() =0;
};

__declspec(dllexport) IConstruction* obj();

-

// DLL implementation
struct Construction : public IConstruction {
  SomeType sTArray[100];

  Construction() { /* do initialization */ }
  virtual void release() { delete this; }
  virtual SomeType& get_array() { return sTArray; }
  virtual ~Construction() { /* do clean up */ }    
};

IConstruction* obj() { return new Construction; }
于 2010-11-30T14:57:24.943 回答