【问题标题】:redefine __LINE__ and __FILE__ constants重新定义 __LINE__ 和 __FILE__ 常量
【发布时间】:2013-12-19 03:29:20
【问题描述】:

我正在为 c++ 制作内存泄漏检测器。它替换了全局new操作符,使用宏初始化两个全局变量__file____line__,如下所示:

#define new (__file__=__FILE__,__line__=__LINE__) && 0 ? NULL : new

我从另一个我不记得名字的 StackOverflow 用户那里学到了这个技巧。这适用于涉及 new 的简单操作,但是当用户为命名空间定义本地 operator new 时,这种方法会导致问题。一方面,像

这样的行
void* operator new(size_t size);

也被宏匹配;此外,显式调用 global new,例如:

int* i = ::new int;

导致语法错误。

有没有办法在部分代码中重新定义或抑制 __LINE__and__FILE__ 常量(以便它们显示对 operator new 的调用的文件名和行号)?如果不是,如何改进宏以不匹配用户定义的“operator new”并且不会导致“::new”出现问题?

我真的很想摆脱宏的怪癖。在此先感谢:)

【问题讨论】:

  • 这就是 C++ 语言定义不允许创建重新定义关键字的宏的原因。
  • 通过重新定义关键字将新值分配给两个全局变量(更糟糕的是,使用保留名称)不会生成泄漏检测器(除非您假设它始终是最后一次泄露的分配)。虽然您已经在使用非标准的东西,但我宁愿建议您使用自定义分配器重载全局 operator newdelete,该分配器会为每个分配记住 __builtin_return_address(1)
  • @Damon 宏不是程序的唯一部分,我确实替换了全局 new 和 delete 运算符。信息存储在一个链表中。

标签: c++ gcc macros


【解决方案1】:

我知道没有办法非侵入式地做到这一点。过去,我使用 regex 或 c++ 函数替换工具(如 Visual Studio 中可用的重构工具)来更改 new 的所有实例,以显式调用记录文件和行号的宏。

另一种选择是检测您的内存系统以记录堆栈帧。此方法具有较高的运行时成本,但如果由于滥用频繁使用的库代码而发生分配而发生泄漏,则有时会很有用。没有平台无关的方法可以做到这一点,请参阅this 问题以获取适用于常见平台(linux 和 windows)的信息。

编辑:对于您的具体情况,您可以取消定义宏并在引起问题的 new 标识符实例之后重新定义它。

【讨论】:

  • 太糟糕了,我正在为一个既没有 Windows 也没有 linux 库可用的平台开发这个应用程序。此外,我确实需要跟踪对 global new 的调用,因此忽略这些行可能是不可行的。
【解决方案2】:

好的,我已经放弃尝试使宏工作了。从外观上看,不能。我已经编写了一个 perl 脚本来完成这项工作。它在预处理(预处理器)之前运行,并且它比 C 预处理器执行的替换更智能。 这些是用于将 new 和 ::new 匹配到其他内容的正则表达式:

$this =~ s/(::)?\s*new([^\w_])/__fl_init(__FILE__,__LINE__)?NULL: $1new$2/g;

我不知道,也许我会写一个批处理文件来自动预处理源。如果有人知道使用 CPP 的解决方法,请发表评论。

【讨论】:

  • 很高兴听到您放弃了努力,因为创建重新定义语言关键字的宏应该是一种犯罪行为,正如 C++ 标准禁止这样做的事实所反映的那样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
  • 1970-01-01
  • 2011-03-04
  • 1970-01-01
  • 2011-05-24
  • 2010-10-10
相关资源
最近更新 更多