再问:堆栈对象的判断

netpole 2006-01-24 10:52:12
有没有在Windows判断对象是否是在堆或栈?Vc.net中有没有提供此类的函数(除_msize之外)呢?在Windows中好象不能使用MC条款27:要求或禁止在堆中产生对象(上)中的 onHeap函数。在Console中,能否使用main入栈后的 EBP = 0x12FEDC来和堆或栈对象的地址作比较,小于该值是栈对象,而大于该值是堆或全局对象吗?而Windows GUI 程序则使用 WinMain入栈后的EBP。如何判断全局对象呢?所有Windows平台中每个程序的栈开始地址都想同吗?有其他方法(适用于Windows)的方法吗?
...全文
565 38 打赏 收藏 举报
写回复
38 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
two_ears 2006-01-26
嗯,传说中的TLS,我也没用过,惭愧一下先。
我想就是系统替我做了管理工作吧
  • 打赏
  • 举报
回复
two_ears 2006-01-26
嗯...这样是不是还需要重载delete,
这样的操作我自己也没试过,不知道会遇到什么问题。
不过,我觉得可以解决。
  • 打赏
  • 举报
回复
two_ears 2006-01-26
嗯,异常不好。
我想的重载new就是想利用非堆内存的分配不调用new呀,
因为new才需要delete,这样,在对象内部完成是否需要delete的标记,
所以不用对构造函数进行改造。而楼主的其他调用都不用变。
  • 打赏
  • 举报
回复
ddddh 2006-01-26
@ 耳朵

“而且其实您刚才判断栈的方法,是不是可以把用于判断的函数和标记栈首的变量封装起来,再加上对线程的判断。”

您说的很对,不过我觉得不一定要封装,可以使用线程局部存储(TLS [thread local storage])来实现。
  • 打赏
  • 举报
回复
ddddh 2006-01-26
@ 耳朵

重载new怎样实现楼主需要的功能呢?

比如
class Widget{...};

但是Widget w; 不会调用你重载的new呀.

使用
delete 栈对象 然后catch异常的办法,如果用户使用了一个从池中分配内存的策略,delete可能只是简单的把这块内存放回到内存池里,未必会发生异常,何况异常毕竟影响性能。

个人浅见,仅供参考:-)
  • 打赏
  • 举报
回复
two_ears 2006-01-26
而且其实您刚才判断栈的方法,是不是可以把用于判断的函数和标记栈首的变量封装起来,再加上对线程的判断。
  • 打赏
  • 举报
回复
two_ears 2006-01-26
ddddh(叶君临),重载new是一个不用加参数的办法,在new操作符调用的时候作标记,这样形式不变
  • 打赏
  • 举报
回复
ddddh 2006-01-26
又看了一下楼主的需求,我觉得倒是有一个简单的办法来做这个事情。

我写过一个类似的东西,也是需要自动销毁对象,我当时的办法是在构造函数里传进一个bool型的参数bAutoDelete,如果对象是用new分配的,我就new CXXX(..., true);如果是在栈上分配的,我就CXXX(...,false);

那么在需要自我销毁的时候,我会判断一下m_bAutoDelete,如果不为真,就直接pass掉,否则销毁自己。


楼主可以参考。毕竟我想,在构造你变量的时候,你是知道它到底是不是用new分配的。何况手动判断对象是否在栈上,过于机器相关,且难以分辨堆和全局变量,我认为不是一个好的办法。

:)

  • 打赏
  • 举报
回复
windows平台上
搜索PE头
得到 栈范围地址,堆范围地址 ,初始化全局变量地址范围,未初始化全局变量范围
然后随便得到变量的地址看看在那个范围内即可。

linux平台上 可执行文件也应该有类似的东西
  • 打赏
  • 举报
回复
whatsouta 2006-01-26
STL提供了一个auto_ptr这个好东西,你为什么不用。
  • 打赏
  • 举报
回复
two_ears 2006-01-26
嗯,ddddh(叶君临),刚才请教我们一老同事,他也给的这个办法,我觉得其实挺好的
  • 打赏
  • 举报
回复
two_ears 2006-01-26
哦,是这种情况呀,嗯...想想

要是我的话,就给Widget构造函数再加个参数。
我觉得没必要为了形式的完美而自找麻烦。

不这样做的话,就在自我释放的时候,一律delete,但使用try和catch(...),来简单的避免一下异常,这样可以吧?当然,人家说不好,但我觉得具体问题具体分析吧。

哦,对了,想没想过,重载Widget的new操作符?
  • 打赏
  • 举报
回复
ddddh 2006-01-26
我想了想,办法还是有的,不过不那么优雅.

你可以引出一个全局变量(void *g_p),线程局部存储也可以,在线程函数的入口,一般是main,或者其他的线程入口函数,申明一个局部变量,将其地址赋给那个全局量。然后判断:

bool IsInStack(void *pObj)
{
  int i;
  return (pObj > &i) && (pObj < g_p);
}

麻烦一点,不过这个我相信是一定能工作的了:)
  • 打赏
  • 举报
回复
netpole 2006-01-26
two_ears 说说你的办法:
//我想的实现大概是这样的。
Widget parent;
Widget child1(&parent); // 将parent设置为child1的父
Widget* child2 = new Widget(&parent); // 将parent设置为child2的父
//当parent行将销毁时,通知所有子Widget进行自我销毁,而child2所对应的空间是通过heap配置而来的,所以child2在自我销毁时需自我delete.而child不是heap对象,所以无须delete。

  • 打赏
  • 举报
回复
CSDNWW 2006-01-26
父类对象析构了, 子类对象一定要析构???
  • 打赏
  • 举报
回复
netpole 2006-01-26
To ddddh(叶君临) :
糟糕,考虑不周。IsOnTheHeap真的不行呀。现在只能试试重载 new 了。苦ing
  • 打赏
  • 举报
回复
ddddh 2006-01-26
@ netpole(往)

你这个函数肯定是不能工作的,不信你可以分配一块大于4M大小的内存试试。


因为我觉得很难平台无关的,优雅的,根据一个地址来判断它是在堆上或者是栈上。所以你这个问题比较现实的做法,我认为就是在你的类里面加上一个成员变量标记它是否在堆上分配,构造对象的时候对其赋值。

你觉得呢?
  • 打赏
  • 举报
回复
netpole 2006-01-26
To ddddh(叶君临) :
我现在使用了这个函数来判断:
//用于VC
bool IsOnTheHeap()
{
long AddrThis = PtrToLong(this);
if(AddrThis > 0x12FFFF && AddrThis < 0x400000)
return true;
return false;
}

对于引入全局变量的想法,我认为不妥当。在什么 g_p 时机下将地址提供给 g_p ,由我的类来进行呢,还是由用户呢?且我要的是判断heap对象。上面的函数在我的电脑里能工作,但不知道在其他Windows会怎么。
在此,谢谢大家的热心帮助!

  • 打赏
  • 举报
回复
two_ears 2006-01-25
sorry, 楼主,还是不太明白,Widget是什么,原谅我,给解释一下。呵呵。
  • 打赏
  • 举报
回复
netpole 2006-01-25
”适时“, 例如当父Widget行将销毁时,自动释放所有子Widget中通过new配置而来的Heap空间。
  • 打赏
  • 举报
回复
加载更多回复(18)
相关推荐
发帖
C++ 语言

6.2w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
帖子事件
创建了帖子
2006-01-24 10:52
社区公告
暂无公告