About DEBUG_NEW

本文详细介绍了在MFC中如何使用DEBUG_NEW宏替代new运算符,以帮助开发者定位内存泄漏问题。通过DEBUG_NEW,可以在调试版本中记录分配内存时的文件名和行号,从而在发生内存泄漏时方便地追溯根源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、在调试模式下,new操作符号通过宏定义转换成了调试版本。

在文件头经常可以发现以下语句:

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

其中,将new定义为DEBUG_NEW

二、DEBUG_NEW的处理

调试版本的new操作函数:void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);

宏替换:#define DEBUG_NEW new(THIS_FILE, __LINE__) //文件名、行号被传入,供调试输出。

实际代码如下:

void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}
//分配内存
void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)
{
#ifdef _AFX_NO_DEBUG_CRT
UNUSED_ALWAYS(nType);
UNUSED_ALWAYS(lpszFileName);
UNUSED_ALWAYS(nLine);
return ::operator new(nSize);
#else
void* pResult;
#ifdef _AFXDLL
_PNH pfnNewHandler = _pfnUninitialized;
#endif
for (;;)
{
pResult = _malloc_dbg(nSize, nType, lpszFileName, nLine);
if (pResult != NULL)
return pResult;
#ifdef _AFXDLL
if (pfnNewHandler == _pfnUninitialized)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
pfnNewHandler = pState-> m_pfnNewHandler;
}
if (pfnNewHandler == NULL || (*pfnNewHandler)(nSize) == 0)
break;
#else
if (_afxNewHandler == NULL || (*_afxNewHandler)(nSize) == 0)
break;
#endif
}
return pResult;
#endif
}
#endif //_DEBUG

 

DEBUG_NEW

  #define new DEBUG_NEW

  说明:

  帮助查找内存错误。用户在程序中使用DEBUG_NEW,用户通常使用new运算符来从堆上分配。在Debug模式下(但定义了一个DEBUG符号),DEBUG_NEW为它分配的每个对象记录文件名和行号。然后,在用户使用CMemoryState::DumpAllObjectSince成员函数时,每个以DEBUG_NEW分配的对象分配的地方显示出文件名和行号。 为了使用DEBUG_NEW,应在用户的资源文件中插入以下指令: #define new DEBUG_NEW 一旦用户插入本指令,预处理程序将在使用new的地方插入DEBUG_NEW,而MFC作其余的工作。但用户编译自己的程序的一个发行版时,DEBUG_NEW便进行简单的new操作,而且不产生文件名和行号消息。

 

以下是MSDN中的内容:   
在   MFC   中,可以使用   DEBUG_NEW   宏代替   new   运算符来帮助定位内存泄漏。在程序的“Debug”版本中,DEBUG_NEW   将为所分配的每个对象跟踪文件名和行号。当编译程序的“Release”版本时,DEBUG_NEW   将解析为不包含文件名和行号信息的简单   new   操作。因此,在程序的“Release”版本中不会造成任何速度损失。   
如果不想重写整个程序来使用   DEBUG_NEW   代替   new,则可以在源文件中定义下面的宏:   
#define   new   DEBUG_NEW  
当进行对象转储时,用   DEBUG_NEW   分配的每个对象均将显示被分配到的文件和行号,使您可以查明内存泄漏源。   
MFC   框架的“Debug”版本自动使用   DEBUG_NEW,但代码不自动使用它。如果希望利用   DEBUG_NEW   的好处,则必须显式使用   DEBUG_NEW   或   #define   new,如上所示。   

转载于:https://www.cnblogs.com/taoxu0903/archive/2008/07/25/1251579.html

// DSplit.cpp : Defines the class behaviors for the application. // #include "stdafx.h" #include "DSplit.h" #include "MainFrm.h" #include "DSplitDoc.h" #include "DSplitView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CDSplitApp BEGIN_MESSAGE_MAP(CDSplitApp, CWinApp) //{{AFX_MSG_MAP(CDSplitApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CDSplitApp construction CDSplitApp::CDSplitApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } ///////////////////////////////////////////////////////////////////////////// // The one and only CDSplitApp object CDSplitApp theApp; ///////////////////////////////////////////////////////////////////////////// // CDSplitApp initialization BOOL CDSplitApp::InitInstance() { // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif // Change the registry key under which our settings are stored. // You should modify this string to be something appropriate // such as the name of your company or organization. SetRegistryKey(_T("Local AppWizard-Generat
最新发布
03-13
<think>好的,用户的问题是关于MFC中的DSplit应用程序类,特别是CDSplitApp的实现和初始化。我需要先理解DSplit是什么,可能是指分割窗口的应用程序。MFC中的文档/视图结构通常使用CSplitterWnd来实现窗口分割,但用户提到的CDSplitApp可能是一个自定义的类,或者是特定项目中的命名。 首先,我应该回忆MFC应用程序的基本结构。MFC应用程序通常有一个从CWinApp派生的应用类,负责初始化和运行。文档类、视图类、框架窗口类和文档模板是核心部分。如果用户提到的DSplit涉及窗口分割,CSplitterWnd的使用是关键,但应用类本身可能不需要直接处理分割窗口,除非有特殊初始化需求。 接下来,用户需要的是CDSplitApp类的实现和初始化的详解。我需要检查标准的MFC应用初始化流程,比如InitInstance方法,其中会创建文档模板,注册文档类型,处理命令行参数等。如果有DSplit特定的功能,比如在初始化时创建分割窗口,可能需要在主框架窗口创建后,通过OnCreateClient方法使用CSplitterWnd。 但根据用户提供的引用,引用的内容似乎涉及NumPy的dsplit、vsplit,以及PyTorch的utils和数据集,这些可能与MFC无关。可能用户混淆了不同技术,或者引用的内容有误。需要确认DSplit是否与NumPy有关,但根据问题上下文,DSplit应该是指MFC中的应用程序类,所以可能引用部分有误,或者用户可能想结合其他技术。但根据问题,应专注于MFC部分。 另外,用户提供的示例是关于快速排序的Python代码,但用户的问题转向了C++ MFC,这可能需要切换技术栈。需要确保回答正确,专注于MFC的应用类实现,即使引用中的内容不相关,可能需要忽略或指出不相关。 可能需要解释CDSplitApp的典型实现步骤,比如从CWinApp派生,重写InitInstance,创建文档模板,主框架窗口,处理命令行等。如果有分割窗口,可能在主框架中创建CSplitterWnd对象,并在OnCreateClient中初始化分割视图。 需要确保回答结构清晰,分步骤说明,代码示例正确,使用中文,并正确应用LaTeX格式。同时生成相关问题,可能涉及MFC应用类初始化、分割窗口创建、文档视图结构等。</think>### MFC中CDSplitApp类的实现与初始化详解 在MFC框架中,`CDSplitApp`类通常是应用程序的主类,继承自`CWinApp`。其核心作用是初始化应用程序实例、管理文档模板及主窗口创建。以下是关键实现步骤: --- #### 1. **类声明与基本结构** ```cpp // DSplitApp.h class CDSplitApp : public CWinApp { public: CDSplitApp(); virtual BOOL InitInstance(); // 必须重写的初始化函数 DECLARE_MESSAGE_MAP() }; ``` --- #### 2. **类实现与初始化流程** ```cpp // DSplitApp.cpp BEGIN_MESSAGE_MAP(CDSplitApp, CWinApp) ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen) END_MESSAGE_MAP() CDSplitApp::CDSplitApp() { // 构造函数可初始化成员变量 } BOOL CDSplitApp::InitInstance() { CWinApp::InitInstance(); // 1. 注册文档模板 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CDSplitDoc), // 文档类 RUNTIME_CLASS(CMainFrame), // 主框架类 RUNTIME_CLASS(CDSplitView)); // 视图类 AddDocTemplate(pDocTemplate); // 2. 解析命令行参数 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 3. 创建主窗口 m_pMainWnd = new CMainFrame; m_pMainWnd->LoadFrame(IDR_MAINFRAME); m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE; } ``` --- #### 3. **分割窗口的集成** 若需实现窗口分割功能,通常在`CMainFrame::OnCreateClient`中操作: ```cpp // MainFrame.cpp BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if (!m_wndSplitter.CreateStatic(this, 1, 2)) // 1行2列分割 return FALSE; m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftView), CSize(200, 0), pContext); m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CRightView), CSize(0, 0), pContext); return TRUE; } ``` --- #### 4. **应用程序对象全局实例化** ```cpp // DSplitApp.cpp CDSplitApp theApp; // MFC要求全局唯一实例 ``` --- ### 关键点说明 1. **文档-视图架构**:通过`CSingleDocTemplate`绑定文档、框架和视图类[^3]。 2. **消息映射**:通过`BEGIN_MESSAGE_MAP`处理菜单/命令响应。 3. **分割窗口**:使用`CSplitterWnd`实现静态或动态分割,需在主框架类中重写`OnCreateClient`[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值