破坏DLL中的单例

时间:2009-10-29 13:21:52

标签: c++ c visual-studio visual-c++ mfc

我正在尝试创建一个简单的Win32 DLL。作为DLL和EXE之间的接口我使用C函数,但在DLL内部我使用C ++单例对象。以下是我的DLL实现的一个示例:

// MyDLLInterface.cpp文件--------------------

#include "stdafx.h"
#include <memory>
#include "MyDLLInterface.h"    

class MySingleton
{
  friend class std::auto_ptr< MySingleton >;
  static std::auto_ptr< MySingleton > m_pInstance;

  MySingleton()
  {
    m_pName = new char[32];
    strcpy(m_pName, “MySingleton”);
  }
  virtual ~ MySingleton()
  {
    delete [] m_pName;
  }

  MySingleton(const MySingleton&);
  MySingleton& operator=(const MySingleton&);

public:
  static MySingleton* Instance()
  {
    if (!m_pInstance.get())
      m_pInstance.reset(new MySingleton);
    return m_pInstance.get();
  }

  static void Delete()
  {
    m_pInstance.reset(0);
  }

  void Function() {}

private:
  char* m_pName;
};

std::auto_ptr<MySingleton> MySingleton::m_pInstance(0);


void MyInterfaceFunction()
{
  MySingleton::Instance()->Function();
}

void MyInterfaceUninitialize()
{
  MySingleton::Delete();
}

// MyDLLInterface.h文件--------------------

#if defined(MY_DLL)
  #define MY_DLL_EXPORT __declspec(dllexport)
#else
  #define MY_DLL_EXPORT __declspec(dllimport)
#endif

MY_DLL_EXPORT void MyInterfaceFunction();
MY_DLL_EXPORT void MyInterfaceUninitialize();

我遇到的问题或问题如下:如果我从我的EXE 退出实例()调用 MyInterfaceUninitialize() ,我有内存泄漏( m_pName 指针)。为什么会这样?看起来EXE退出后发生 MySingleton 的破坏。是否可以强制DLL或EXE稍早销毁 MySingleton ,所以我不需要调用 MyInterfaceUninitialize()函数?

修改 感谢您的帮助和解释。现在我明白这是一个设计问题。如果我想继续使用我当前的解决方案,我需要在我的EXE中调用 MyInterfaceUninitialize()函数。如果我不这样做,它也没关系,因为当它离开EXE范围时,单身就会自我毁灭(但我需要忍受令人不安的调试器消息)。避免这种行为的唯一方法是重新考虑整个实现。

我还可以将我的DLL设置为Visual Studio中Linker-&gt; Input下的“Delay Loaded DLLs”,以摆脱令人不安的调试器消息。

3 个答案:

答案 0 :(得分:3)

  

如果我没有从我的EXE ExitInstance()调用MyInterfaceUninitialize(),我有内存泄漏( m_pName 指针)。为什么会这样?

这不是泄漏,这是auto_ptr应该工作的方式。它们在超出范围时释放实例(在您的情况下是卸载dll的时候)。

  

看起来,在EXE退出后,MySingleton遭到破坏。

  

是否可以强制DLL或EXE稍早破坏MySingleton,所以我不需要调用MyInterfaceUninitialize()函数?

不是没有调用此函数。

答案 1 :(得分:2)

您可以利用DllMain callback function在加载/卸载DLL或进程/线程附加/分离时采取适当的操作。然后,您可以为每个连接的进程/线程分配对象,而不是使用单例,因为此回调函数在附加线程的上下文中执行。考虑到这一点,还要看看Thread Local Storage (TLS)

答案 2 :(得分:1)

老实说,对于您提供的示例,如果从ExitInstance调用Uninitialize方法并不重要。是的,调试器会抱怨未释放的内存,但是再次,它是一个单例,它的目的是延长一段时间。

只有在DLL中有一些需要在退出时保留的状态信息,或者如果您多次动态加载/卸载DLL时,您是否需要勤勉地进行清理。否则,只是让操作系统在退出时拆除进程就好了,报告的内存泄漏在这一点上是无关紧要的。