这个在DLL中初始化数组的设计有什么问题吗?

发布于 2024-10-05 08:47:50 字数 467 浏览 5 评论 0原文

假设我们有一个 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;

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

野侃 2024-10-12 08:47:50

是的,你已经为自己在某个时刻遭遇了非常令人讨厌的意外做好了准备。

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

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

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.

笑梦风尘 2024-10-12 08:47:50

由于 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; }

Since CRT in the DLL and in the executable could be different you should supply Construction with a release method that will delete allocated object. In this way you will guarantee that the deallocation function will be called from the appropriate CRT. Also you need to return Construction by pointer to exclude copying operations. The following code illustrates the method how it could be implemented:

// 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; }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文