发出跨Windows DLL模块边界清理堆分配资源的问题

时间:2017-02-14 06:10:12

标签: c++ unique-ptr

/* 

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

这一切都对我有意义,我认为我可能会使用std::unique_ptr来帮助保持组织有序。这是我使用的方法。 (我目前没有方便的编译器,但我认为这些片段/伪代码足够清晰,可以传达我的意图:

*/

Library.h

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

您可以看到我的库和主程序都使用相同的头库Library.h。我创建变量local来保存指向我的库的指针。 GetMyLibrary方法(在DLL中调用)为我传入的引用分配和分配new unique_ptr。我在“第1点”使用赋值,因为我希望从DLL的上下文中删除Deleter用于清理,不是最初分配给主程序中local变量的Deleter。意思是,当本地超出范围时,我希望它的清理触发DLL的Deleter,而不是最初分配给它的那个(即我使用library = Ptr(new MyLibrary)而不是library.reset(new MyLibrary),因为我想要删除从DLL的上下文中调用

无论如何,程序似乎工作,除了在清理期间,当本地unique_ptr破坏时,我得到一个堆损坏异常(在调试中),这让我相信我正在删除错误的堆(即。unique_ptr的行为不符合我的预期。

最终,我最终以另一种方式解决了这个问题似乎更加清晰,但我只是好奇为什么上面的方法失败了?

1 个答案:

答案 0 :(得分:1)

您的删除操作是unique_ptr的一部分,当指针超出范围时,将从main调用。

你应该在DLL中提供GetMyLibrary() / FreeMyLibrary()并在那里处理内存分配/释放(在应用程序端使用RAII),或者将分配器传递给GetMyLibrary()并进行内存分配和解除分配申请的责任。