在DLL中分配内存并将指针指向客户端应用程序是不好的做法吗?

Nav*_*Nav 13 c++ design-patterns

我正在使用动态加载DLL的exe.DLL中的函数在堆上分配内存并将指向该内存的指针传递给exe.

一位大四学生表示这样做是不好的做法.他说,如果我必须在exe和DLL之间共享内存,exe必须分配内存并将指针传递给DLL,反之亦然.这是真的?为什么?

编辑:在我的情况下,我计划在DLL本身内分配和释放内存.

kum*_*ran 12

设计模式背后的基本思想之一是所有权.这个想法是 - one who creates a resource (and thereby holds it in the pointer) should be responsible for deleting the resource.这将确保设计的神圣性和项目的更长寿命,其开发人员可以看到较小的错误.

所以现在在你的情况下,DLL可以通过任何可执行文件附加,他可以尝试删除资源,这可能会导致未来的问题.所以我认为反之亦然,我会说这是一个合理的建议.

  • 虽然所有权方面是一个很好的原则,但这种答案忽略了.exe和.dll可能使用不同分配器的实际技术原因.例如,假设您正在使用.dll的发布版本和.exe的调试版本,它使用一些特殊的调试版本的`malloc`和`free`. (2认同)
  • 使用Microsoft crt内存分配/解除分配从调试到发布不兼容.您无法在调试dll中安全地分配内存并在release exe或viseversa中释放它. (2认同)

jam*_*lin 11

这里有一些让调用者提供指针的原因:

  1. 对称所有权语义.其他几个答案已经解释了这一点.
  2. 避免分配器和解除分配器不匹配. 正如Esthete的回答中提到,如果DLL分配指针并返回它,则调用者必须调用相应的解除分配器来释放它.这不一定是微不足道的:DLL可能静态链接到一个版本,比如malloc/,free.exe链接到不同版本的malloc/ free.(例如,当.exe使用专门的调试版本时,DLL可能正在使用发行版本.)
  3. 灵活性. 如果DLL用于一般用途,让调用者分配内存可为调用者提供更多选项.假设调用者不想使用malloc,而是希望从某个特定的内存池中分配内存.也许这是调用者可以提供指向堆栈上分配的内存的指针的情况.如果DLL分配了内存本身,则调用者没有任何这些选项.

(第二点和第三点也可以通过.exe为DLL代码提供分配器/解除分配器来解决.)


Aes*_*ete 7

我以前见过这个问题,它是由DLL和exe不同地连接到CRT(静态,动态MT等)引起的.

我要在DLL和可执行文件之间传递指向内存的指针,它们都应该提供某种Free()功能来从各自的堆中释放内存.


Dam*_*mon 5

通常,堆(The One Heap)属于进程,并且从哪里分配并不重要,所以这将正常工作,除非它没有.

因此,声称它是"不良做法"是有效的.有些东西比工作正常的东西更糟糕,除非它没有.

关于它的最糟糕的部分是,当一切都爆炸时,并不是立即明显出现了什么问题,你很容易在不知情的情况下遇到问题.它可能就像将特定版本的CRT链接到您的DLL一样简单.或者您团队中的某些人可能由于某种原因创建了一个单独的堆.或者,其他一些原因并不是很明显导致另一个堆被创建的原因.

是什么让自由错误堆的情况变得如此恶劣,以至于你通常不知道将会发生什么,或何时(或者如果有人会注意到).

您可以从堆函数异常中获取NULL返回值.您的应用程序可能已为其中任何一个准备好,或者可能不是(说实话,您总是检查返回值,不是吗?).它可能在释放后立即崩溃,或者您可能只是在几分钟或几小时后默默地泄漏内存并耗尽地址空间(或内存),并且没有人会知道原因.或者是其他东西.
因此,您所看到的可能根本不会与导致问题的因素(明显)相关联.


Wal*_*ter 5

我只想指出,将分配器传递给 DLL 来分配内存是完全安全的,并且是 C++ std 库本身使用的标准模型。在这种情况下,分配是由 DLL 通过调用者传递的方法完成的,避免传递指针,并避免链接到不同实现的问题malloc()