检测动态分配的对象?

Posted

技术标签:

【中文标题】检测动态分配的对象?【英文标题】:Detect dynamically allocated object? 【发布时间】:2011-09-15 16:14:36 【问题描述】:

我可以检查一个对象(通过指针或引用传递)是否是动态分配的?

例子:

T t;
T* pt = new T();
is_tmp(&t); // false
is_tmp(pt); // true

上下文

我完全意识到这听起来像是糟糕的设计,事实上确实如此,但我正在尝试扩展我不能(或不应该不)修改的代码(当然我责怪代码不是我的;))。它调用一个方法(我可以覆盖),该方法将delete 传递的对象以及仅适用于动态分配的对象的其他内容。现在,我想检查一下我是否有可以成为deleted 的东西,或者它是否是临时的。

我永远不会传递一个全局(或静态)变量,所以我将这个未定义,留在这里。

【问题讨论】:

How can I tell if an object is statically or dynamically allocated on the constructor? 的可能重复项 请注意,另一个(尽管较旧)问题已作为此问题的副本关闭,因此将其作为另一个问题的副本关闭可能不是一个好主意(循环参考)。跨度> 【参考方案1】:

不便携。在 PC 上的 Solaris 或 Linux(至少 32 位 Linux)下, 堆栈位于可用内存的最顶端,因此您可以比较 地址传入一个局部变量的地址:如果地址 传入的高于局部变量的,它的对象 指向是局部变量或临时变量,或者是 a 的一部分 局部变量或临时变量。然而,这种技术调用 undefined 左右行为——它恰好适用于两者 我提到的平台(并且可能适用于所有平台 堆栈位于可用内存的顶部并向下增长)。

FWIW:您还可以检查这些机器上的静态数据。所有的静力学都是 在内存的底部,链接器插入符号end 他们的结束。所以用这个名字声明一个外部数据(任何类型), 并将地址与之比较。

关于可能删除对象,但是......只是知道 对象不在堆上(也不是静态的)是不够的。这 对象可能是更大的动态分配对象的成员。

【讨论】:

嗯,我也有类似的想法,但我的潜意识立即将其丢弃为危险和令人毛骨悚然​​>。感谢您确认这一点:) 检查指针的值是一个非常有趣的想法,但不知何故感觉非常非常错误:-) 如果对象是动态分配对象的成员怎么办? @bitmask 这绝对不是我想在可移植代码中尝试的东西,或者我的应用程序是否依赖它。 (我在assert 中使用过一次,以确保对象是动态分配的;有更好的方法可以做到这一点,但那时我只使用 C++ 6 个月,并不知道它们.当然,如果测试确实引起了问题,我们可以删除assert。) 如果你运行多线程也会遇到问题,在这种情况下,额外线程的堆栈通常分配在堆上...... @Chris Dodd 那也是。尽管您可能可以通过一个公共点运行所有线程启动函数并跟踪它们的堆栈地址。但是我在线程存在之前使用了它,所以这个问题从未出现过。 (正如我所说:我没有在生产代码中使用它——仅用于调试。我绝对推荐它。)【参考方案2】:

通常,正如 DeadMG 所说,您无法从指针中分辨出它来自何处。但是,作为调试、移植或分析措施,您可以将成员 operator new 添加到跟踪动态分配的类中(前提是没有人使用显式的全局 ::new -- 恐怕包括容器)。然后,您可以建立一个动态分配内存的set<T*> 并在其中搜索。

这根本不适合任何严肃的应用程序,但也许这可以帮助您跟踪事情的来源。您甚至可以将带有行号的调试消息添加到您的操作员。

【讨论】:

对调试肯定有好处,但我已经知道谁调用了什么,所以这属于严重的应用程序 @bitmask:在生产代码中,您需要一个函数来可选地删除一个对象,这取决于它是如何分配的,这是非常麻烦的。 (例如,您可能永远无法在容器中安全地使用您的对象。)new 重载的问题是您也无法阻止人们使用::new。所以真的没有好的解决方案,你所做的任何事情都取决于你能保证所有那些回避你的跟踪的事情都不会发生。 我知道,troublesome 甚至没有开始准确地描述我在这里所做的事情。 您可以覆盖全局 ::new(以及 ::new[] 和 ::delete 和 ::delete[])并跟踪堆分配的每一块内存,但这并不便宜,也不容易. @Chris:您不能覆盖新的全局展示位置。 (有一个很好的理由!!)【参考方案3】:

不,不可能知道。您应该修复错误。在最少的情况下,您可以使用智能指针(如 shared_ptr),如果您不想删除它,可以给它一个空的自定义析构函数。

【讨论】:

我正在扩展/连接我无法更改的代码(尤其是签名)。所以我的选择非常有限。但是,我可以随意装饰对象,所以我会这样做,但如果您可以简单地检查一些内置语言,我想避免这种开销。【参考方案4】:

如果您有权访问动态内存分配器代码本身,则可以扫描内部结构并查看当前指针是否在其分配的列表/堆栈/区域中,或者它正在被存储。很多时候,它们被存储为链表样式结构,扫描你的 var 的地址不会太难。

【讨论】:

【参考方案5】:

在我看来应该是可能的 因为你可以检查内存是在堆上还是在栈上 这将是高度依赖平台的代码

首先你必须得到堆的范围,然后你必须检查传递的内存地址是否在这个范围内...... (听起来很简单,但第一步可能很棘手:-))

【讨论】:

这当然是可能的(参见 James Kanze 的回答),但这是一个可怕的 hack,所以我不会这样做。

以上是关于检测动态分配的对象?的主要内容,如果未能解决你的问题,请参考以下文章

类对象的动态分配以及释放

为啥 Objective-C 对象必须动态分配?

指向对象的指针数组的动态分配

处理包含动态分配成员的对象向量

获取动态分配的数组大小

动态内存分配