简体   繁体   English

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

[英]Is it bad practice to allocate memory in a DLL and give a pointer to it to a client app?

I'm using an exe which dynamically loads a DLL. 我正在使用一个动态加载DLL的exe。 A function in the DLL allocates memory on the heap and passes a pointer to that memory to the exe. DLL中的函数在堆上分配内存,并将指向该内存的指针传递给exe。

A senior says that it is bad practice to do so. 一位长者说这样做是不好的做法。 He says that if I ever have to share memory between the exe and the DLL, the exe has to allocate memory and pass a pointer to that to the DLL, and not vice versa. 他说,如果我必须在exe和DLL之间共享内存,则exe必须分配内存并将指向该DLL的指针传递给DLL,而不是相反。 Is this true? 这是真的? Why? 为什么?

EDIT: In my case, I planned to allocate and deallocate memory inside the DLL itself. 编辑:就我而言,我计划在DLL本身内部分配和取消分配内存。

One of the basic idea behind the design patterns is ownership. 设计模式背后的基本思想之一就是所有权。 The idea is - one who creates a resource (and thereby holds it in the pointer) should be responsible for deleting the resource . 这个想法是- one who creates a resource (and thereby holds it in the pointer) should be responsible for deleting the resource This will ensure the sanctity of the design and in longer life of the projects, its developer can see lesser bugs. 这将确保设计的神圣性,并在更长的项目寿命中,其开发人员可以看到较少的错误。

So now it in your case, the DLL can be attached by any executable and he can try to delete the resource, which may cause future problem. 所以现在就您而言,DLL可以由任何可执行文件附加,并且他可以尝试删除资源,这可能会导致将来出现问题。 So I think it has been suggested for vice-versa and I would say it as a sound advice. 因此,我认为反之亦然,我认为这是一个合理的建议。

Here are some reasons for having the caller supply a pointer: 这是让调用者提供指针的一些原因:

  1. Symmetric ownership semantics. 对称所有权语义。 This is already explained by several other answers. 其他几个答案已经说明了这一点。
  2. Avoids mismatching the allocator and deallocator. 避免不匹配分配器和取消分配器。 As mentioned in Aesthete's answer , if the DLL allocates a pointer and returns it, the caller must call the corresponding deallocator to free it. Aesthete的答案中所述 ,如果DLL分配了一个指针并返回它,则调用者必须调用相应的释放器以释放它。 This is not necessarily trivial: the DLL might be statically linked against one version of, say, malloc / free while the .exe is linked against a different version of malloc / free . 这不一定是琐碎的:DLL可能与malloc / free一个版本静态链接,而.exemalloc / free的另一个版本链接。 (For example, the DLL could be using release versions while the .exe is using specialized debug versions.) (例如,DLL可能使用发行版,而.exe使用专门的调试版本。)
  3. Flexibility. 灵活性。 If the DLL is meant for general use, having the caller allocate the memory gives the caller more options. 如果DLL是供一般使用的,则让调用方分配内存可以为调用方提供更多选项。 Suppose the caller doesn't want to use malloc and instead wants memory to be allocated from some specific memory pool. 假设调用者不想使用malloc ,而是希望从某个特定的内存池中分配内存。 Maybe it's a case where the caller could provide a pointer to memory allocated on the stack. 也许在这种情况下,调用者可以提供一个指向堆栈上分配的内存的指针。 If the DLL allocated the memory itself, the caller does not have any of these options. 如果DLL本身分配了内存,则调用者将没有任何这些选项。

(The second and third points also mostly can be addressed by having the .exe supply an allocator/deallocator for the DLL code to use.) (第二点和第三点也可以通过让.exe为DLL代码提供分配器/释放器来解决。)

I have seen this issue before, and it is caused by the DLL and exe linking differently to the CRT (static, dynamic MT etc). 我之前已经看到过此问题,它是由DLL和exe链接到CRT(静态,动态MT等)的方式不同引起的。

I you're going to pass a pointer to memory between DLL and executable, they should both provide some sort of Free() functionality to free memory from their respective heaps. 我将在DLL和可执行文件之间传递指向内存的指针,它们都应提供某种Free()功能以从各自的堆中释放内存。

Generally, the heap (The One Heap) belongs to the process, and it does not matter where you allocate from, so this will work just fine, except when it doesn't . 通常,堆(一个堆)属于该进程,并且从哪里分配都没有关系,因此这可以正常工作, 除非不是

Therefore, the claim that it is "bad practice" is valid. 因此,声称它是“不良做法”是有效的。 There are few things that are worse than something that works fine, except when it doesn't. 除能正常工作外,几乎没有什么能比正常工作更糟糕。

The worst part about it is that when everything blows up, it's not immediately obvious what's wrong, and you can easily run into an issue without knowing. 最糟糕的是,当一切都崩溃时,并不能立即清楚地知道出了什么问题,而且您很容易在不知不觉中遇到问题。 It may be something as easy as linking the a particular version of the CRT into your DLL. 将CRT的特定版本链接到您的DLL中可能很容易。 Or someone in your team might have created a separate heap for some reason. 或者您的团队中的某人可能出于某种原因创建了单独的堆。 Or, some other reason that isn't immediately obvious which caused another heap being created. 或者,导致立即创建另一个堆的其他原因(不是立即显而易见的)。

What makes the free-from-wrong-heap situation so vicious is that you don't generally know what will happen, or when (or if someone will notice). 导致错误重堆的情况如此恶毒的原因是,您通常不知道会发生什么事情,何时发生(或者是否有人注意到)。

You may get a NULL return value from a heap function or an exception. 您可能从堆函数异常中获得NULL返回值。 Your application might be prepared for either of them or it might not be (be honest, you always check return values, don't you?). 您的应用程序可能已经为它们中的一个做好了准备,或者可能没有准备好(老实说,您总是检查返回值,不是吗?)。 It might crash immediately upon freeing, or you might just silently leak memory and run out of address space (or memory) minutes or hours later, and nobody will know why. 它可能在释放后立即崩溃,或者您可能只是默默地泄漏了内存并在数分钟或数小时后用完了地址空间(或内存),而没人知道原因。 Or, something else. 或者是其他东西。
Thus, what you see may not at all be in (apparent) correlation to what caused the problem. 因此,您所看到的可能与造成问题的原因根本没有(明显的)相关性。

I only want to point out that passing an allocator to the DLL to allocate memory is perfectly safe and is the standard model used by the C++ std library itself. 我只想指出, 将分配器传递给DLL来分配内存是完全安全的,并且是C ++ std库本身使用的标准模型。 In this case, the allocation is done by the DLL via a method passed from the caller, avoiding to pass pointers , and avoiding the issue of linking to different implementations of malloc() . 在这种情况下,分配是由DLL通过从调用方传递的方法来完成的, 避免传递指针 ,并且避免链接到malloc()不同实现的问题。

the exe and the dll may have different heaps. exe和dll可能具有不同的堆。 when either try to free memory allocated by the other the free fails and there is a leak. 当任何一个尝试释放对方分配的内存时,释放都会失败,并且会发生泄漏。

only if both, the exe and the dll use CRT dynamically with the same version of the CRT they use the same heap. 仅当exe和dll都使用相同版本的CRT动态使用CRT时,它们才使用相同的堆。

so it is a very good advice to do allocation and free in the same binary. 因此,在同一二进制文件中进行分配和释放是一个很好的建议。

I'd argue that it is generally bad practice to hand around raw pointers. 我认为交出原始指针通常是不好的做法。 In case of a dll, it should return a smart-pointer that has a custom deleter that appropriately handles the cleanup (options are std::unique_ptr , std::shared_ptr or boost::shared_ptr in order of preference). 如果是dll,则应返回一个具有自定义删除程序的智能指针,该删除程序可以适当地处理清除(按偏好顺序,选项为std::unique_ptrstd::shared_ptrboost::shared_ptr )。

In fact, it is probably safer to use std::weak_ptr or boost::weak_ptr - these require you to check each time you want to access the resource, because the dll might have been unloaded in the meantime. 实际上,使用std::weak_ptrboost::weak_ptr可能更安全-这些都要求您每次访问资源时都要检查一次,因为在此期间dll可能已被卸载。

正如@kumar_m_kiran所指出的,这与所有权问题有关,但是我想指出的是,@ aleguna也是正确的,因此,恕我直言,正确的规则是“在DLL或EXE中分配和释放相同的内存,但不能同时在两者中分配和释放相同的内存” 。

It's not necessarily bad practice but it's dangerous practice (and probably bad). 这不一定是不好的做法,但它是危险的做法(并且可能是不好的)。 You need to carefully think about who is responsible for freeing the memory. 您需要仔细考虑谁负责释放内存。 The exe will probably not be able to (or should not be able to) free the DLL's memory directly itself so presumably will be passing this pointer back to the DLL at some later date. 该exe可能无法(或不应该)直接直接释放DLL的内存,因此大概在以后的某个日期将该指针传递回DLL。 So now we're passing a pointer back and forth between an EXE and a DLL which isn't nice. 所以现在我们在EXE和DLL之间来回传递指针,这不是很好。

I'd say no, it's not "bad practice". 我会说不,这不是“坏习惯”。 From my experience, you just need to be careful that you release that pointer in the right memory space. 根据我的经验,只需要小心在正确的内存空间中释放该指针即可。 I've built a graphics engine that allocated assets in multiple DLLs (each DLL represented a mini game); 我已经建立了一个图形引擎,可以在多个DLL中分配资产(每个DLL代表一个迷你游戏)。 using a shared_ptr (at the time it was Boost, however, I'm sure the C++11 (or newer) std::shared_ptr supports the same semantics). 使用shared_ptr(但是当时是Boost,但我确定C ++ 11(或更新版本)std :: shared_ptr支持相同的语义)。 I would supply a function that would delete the memory in the right space. 我提供的功能将删除正确空间中的内存。 The main concern, at this point, is that you ensure you free your shared_ptrs before you free the DLL. 在这一点上,主要的考虑是要确保在释放DLL之前先释放shared_ptrs。 I can't recall now, but we might have used a list of shared_ptrs owned by the DLL/DLL wrapper, and all other uses of the pointer were through a weak_ptr TO that shared_ptr. 我现在不记得了,但是我们可能已经使用了DLL / DLL包装器所拥有的shared_ptrs列表,并且指针的所有其他使用都是通过对该shared_ptr的weak_ptr实现的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM