C++ 清理跨Windows DLL模块边界的堆分配资源时出现问题

C++ 清理跨Windows DLL模块边界的堆分配资源时出现问题,c++,unique-ptr,C++,Unique Ptr,我的理解是,将一个或多个动态链接库DLL加载到其地址空间的Windows进程将与所有加载的DLL共享该地址空间,这意味着这些DLL可以读取和写入进程地址空间中的任何内存。但是,当在堆上分配对象时,每个模块(无论是.exe还是进程加载的DLL之一)都从自己的堆中分配。因此,针对执行分配的同一堆取消分配内存是至关重要的 这一切对我来说都是有意义的,我想我可能会使用std::unique\u ptr来帮助保持事情的条理化。这就是我使用的方法。目前我手头没有编译器,但我认为这些代码片段/伪代码将足够清楚

我的理解是,将一个或多个动态链接库DLL加载到其地址空间的Windows进程将与所有加载的DLL共享该地址空间,这意味着这些DLL可以读取和写入进程地址空间中的任何内存。但是,当在堆上分配对象时,每个模块(无论是.exe还是进程加载的DLL之一)都从自己的堆中分配。因此,针对执行分配的同一堆取消分配内存是至关重要的

这一切对我来说都是有意义的,我想我可能会使用std::unique\u ptr来帮助保持事情的条理化。这就是我使用的方法。目前我手头没有编译器,但我认为这些代码片段/伪代码将足够清楚地传达我的意图:

/* 
图书馆

您可以看到我的库和主程序都使用相同的头库。我创建变量local来保存指向我的库的指针。在DLL中调用的GetMyLibrary方法为我传入的引用分配并分配一个新的唯一\u ptr。我在第1点使用赋值,因为我希望DLL上下文中的删除程序用于清理,而不是最初分配给主程序中局部变量的删除程序。也就是说,当local超出范围时,我希望它的清理触发DLL的删除器,而不是最初分配给它的删除器,即我使用library=Ptrnew MyLibrary而不是library.resetnew MyLibrary,因为我希望从DLL的上下文调用删除器

无论如何,该程序似乎可以正常工作,但在清理过程中,当本地unique_ptr破坏时,我在debug中遇到堆损坏异常,这让我相信我从错误的堆中删除了,即unique_ptr没有按照我的预期运行


最终,我以另一种看起来更简洁的方式解决了这个问题,但我只是好奇为什么上面的方法失败了?

您的删除器是unique_ptr的一部分,当指针超出范围时,会从main调用它


您应该在DLL中提供GetMyLibrary/FreeMyLibrary,并在应用程序端使用RAII处理内存分配/释放,或者将分配器传递给GetMyLibrary,并由应用程序负责内存分配和释放。

堆-这是您的主要问题。就Windows而言,堆是由返回的,并且该堆在EXE和DLL之间共享,因此称为进程堆。感谢链接,我将详细阅读。感谢您的回答…我仍然有点困惑。我明白你所说的关于使用get/Free导出的意思……这就是我过去通常的做法,但我不太明白为什么我上面的方法会失败。当我调用GetMyLibrary导出时,DLL中的代码将执行以实例化唯一的\u ptr并新建库的实例。该唯一的\u ptr有一个自定义删除程序,它驻留在DLL代码中,用于释放相应的对象。因此,当我通过ref将unique_ptr从DLL复制到main中的unique_ptr时,我希望调用DLL中的Deleter,类似于调用您提到的FreeMyLibrary函数,我缺少什么?这里的Deleter类型是ptr类型的一部分。我相信,unique_ptr在构造或第一次调用get_Deleter时实例化了Deleter类型的这个对象,这两种情况都发生在您的main中。您可以将普通函数作为deleter传递,但在dll/app边界上使用unique_ptr并不是最好的主意。想象一下,如果dll是用不同的编译器或标准库编译的,甚至是用不同版本的编译器或标准库编译的。出于某种原因,我认为Deleter仅仅是一个在运行时动态分配的函子,而不是唯一的_ptr模板中的一个类型,这一切现在都有意义了。谢谢你的回答。
*/
class ILibrary
{
   public:
   virtual void DoStuff() = 0;
};

struct Deleter
{
  void operator()(ILibrary *p)
  {
    delete p;
  }
};

typedef std::unique_ptr<ILibrary, Deleter> Ptr;

//*MyLibrary.dll*
//Includes Library.h
//Exports:

void GetMyLibrary(Ptr & library)
{
    library = Ptr(new MyLibrary);  // point (1)
}

//**Program.exe**
//Includes Library.h
//Imports MyLibrary.dll (GetMyLibrary export)

int main()
{
    Ptr local;
    MyLibrary->GetMyLibrary(local);
    local->DoStuff();
} // heap corruption on cleanup