关于C++中常用的对DEBUG_NEW、THIS_FILE重定义的说明

时间:2021-07-19 03:32:14

//=============================================================================

#ifdef _DEBUG // 判断是否定义_DEBUG
#define new DEBUG_NEW // 定义调试new宏,取代new关键字
#undef THIS_FILE // 取消THIS_FILE的定义
static char THIS_FILE[] = __FILE__; // 定义THIS_FILE指向文件名
#endif // 结束

//=============================================================================
// 解释:

// 上段代码基本含义:
// 调试状态下编译,修改两个符号的定义。作用就是防止内存泄露和减小程序编译开销。

THIS_FILE 是一个 char 数组全局变量,字符串值为当前文件的全路径,调试状态中当程序出错时出错处理代码可用这个变量告诉你是哪个文件中的代码有问题。
DEBUG_NEW 可以定位内存泄露并且跟踪文件名和行号。

ANSI C 的6个宏:
__FILE__  // 为预编译器常量,返回当前编译的文件名;
__LINE__  // 编译器正在编译文件的第几行;
__DATE__  // 返回当前的日期。如:Jul-20-2004;
__TIME__  // 返回当前的时间。如:hh:mm:ss; 
__TIMESTAMP__  // 返回时间戳信息。在太平洋标准的时间内无论本地时间和 CL.EXE 的运行位置在计算机上的时区。
__STDC__  // 条件编译,意思是:如果定义了标准C或c++,那么编译这句话后面直到#endif以前的源代码。
_STDC__ cplusplus // 这两个都是标准宏,_STDC_表示是是否符合标准C;_cplusplus表示是否是C++。

为了检测内在泄露, Debug 版本的 new 附加上了调用 new 的文件名与调用所在的行号信息, 这是通过 __FILE__ 和 __LINE__ 来实现的, 这两个属于预定义的内部宏,
如果不想重写整个程序来使用 DEBUG_NEW 代替 new,则可以在源文件中定义下面的宏:

#define new DEBUG_NEW

当进行对象转储时,用 DEBUG_NEW 分配的每个对象均将显示被分配到的文件和行号,这样可以查明内存泄漏源。

//-----------------------------------------------------

static char THIS_FILE[] = __FILE__; 解释:

在 DEBUG_NEW 的定义中没有直接使用 __FILE__,而是用了 THIS_FILE,其目的是为了减小目标文件的大小。
多次使用__FILE__宏,虽然得到字符串的内容相同,但是可能地址不同,即同一个字符串常量多次用到时占用不同的地址,这样导致需要的内存增加了。
假设在某个 cpp 文件中有 100 处使用了new,如果直接使用__FILE__,那编译器会产生100个常量字符串,这100个字符串都是这个cpp文件的路径名,最后生成的目标文件会很大,显然十分冗余。
如果使用THIS_FILE,编译器只会产生一个常量字符串,那 100 处 new 的调用使用的都是指向常量字符串 THIS_FILE 指针。

在MFC中,可以使用 DEBUG_NEW 宏代替 new 运算符来帮助定位内存泄漏。在程序的“Debug”版本中,DEBUG_NEW 将为所分配的每个对象跟踪文件名和行号。
当编译程序的“Release”版本时,DEBUG_NEW 将解析为不包含文件名和行号信息的简单 new 操作。因此,在程序的“Release”版本中不会造成任何速度损失。

//=============================================================================


#ifdef _DEBUG
virtual void AssertValid() const; // 有效的断言
virtual void Dump(CDumpContext& dc) const; // 存储上下文
#endif

//=============================================================================
// 解释:

// 当前编译模式为debug时,省略号里的内容有效。
#ifdef _DEBUG
...
#endif

// 检查可用性,即是否有效。
virtual void AssertValid() const;

// 若未更改,则最终调用CWnd::Dump();输出窗口类名,标题名等一系列信息。
virtual void Dump(CDumpContext& dc) const; 

//=============================================================================


说明:这些总结是参照了好几篇文章总结的,怕以后忘记,特此记载。不过参照的文章地址找不着了,在这里无法注明,请见谅!

//=============================================================================