请问怎么判定一个指针指向的对象是栈内存还是堆内存
请教如何判定一个指针指向的对象是栈内存还是堆内存
我想请教下各位大侠, 如何判定一个指针指向的对象是栈内存还是堆内存(new ,malloc 分配的),例如函数参数是个指针,如何知道其所指对象是不是new,malloc分配的内存。
还有如果该对象是栈内存,却调用delete操作,会有什么具体的后果?
多谢多谢!
我就能给这么多分了:)
------解决方案--------------------
呵呵
那如果对象是栈内存,却调用delete操作,会有什么具体的后果?
会提示改指针指向的不是一个有效的堆内存块,调用delete时,在真正释放堆内存前
会有很多检查的(一些检查函数的调用),你可以跟踪一下底层的汇编代码看看
第一个问题应该没有通用的方法吧,不过如果针对于“当前当时”的机器,你可以看看你
第一次分配的栈内存的起始地址是多少A1,第一次动态分配的内存的起始地址是多少A2。。。。。。
默认情况下栈的大小是1M(好像是),然后比较一下
不过这样做没有意思
你可能想在函数内释放外面传进来的指向动态分配内存的指针,建议不要这样做,
在函数外面分配的就在函数外面释放,函数像是一种接口,别人调用你的函数时,
根本不清楚也没有必要知道函数的实现细节,如果你在函数里面释放了动态分配的内存,
知道函数实现细节的还好,万一不知道的,他在调用完函数后又释放一次动态分配的内存
程序肯定会出错的!!
------解决方案--------------------
对于单线程,可以判断指针指的内存是否在用户栈中
多线程不好办
我想请教下各位大侠, 如何判定一个指针指向的对象是栈内存还是堆内存(new ,malloc 分配的),例如函数参数是个指针,如何知道其所指对象是不是new,malloc分配的内存。
还有如果该对象是栈内存,却调用delete操作,会有什么具体的后果?
多谢多谢!
我就能给这么多分了:)
------解决方案--------------------
呵呵
那如果对象是栈内存,却调用delete操作,会有什么具体的后果?
会提示改指针指向的不是一个有效的堆内存块,调用delete时,在真正释放堆内存前
会有很多检查的(一些检查函数的调用),你可以跟踪一下底层的汇编代码看看
第一个问题应该没有通用的方法吧,不过如果针对于“当前当时”的机器,你可以看看你
第一次分配的栈内存的起始地址是多少A1,第一次动态分配的内存的起始地址是多少A2。。。。。。
默认情况下栈的大小是1M(好像是),然后比较一下
不过这样做没有意思
你可能想在函数内释放外面传进来的指向动态分配内存的指针,建议不要这样做,
在函数外面分配的就在函数外面释放,函数像是一种接口,别人调用你的函数时,
根本不清楚也没有必要知道函数的实现细节,如果你在函数里面释放了动态分配的内存,
知道函数实现细节的还好,万一不知道的,他在调用完函数后又释放一次动态分配的内存
程序肯定会出错的!!
------解决方案--------------------
对于单线程,可以判断指针指的内存是否在用户栈中
多线程不好办
- C/C++ code
//测试指针所指内存在栈中,还是堆中 #include <iostream> using namespace std; void* stack_bottom=NULL; void test(); void ptr_in_stack(void* ptr) { //此函数被调用时,一定是在栈顶的 void* stack_top=&stack_top;//获取栈顶位置 if( stack_bottom>ptr && stack_top<ptr)//比较地址范围 { cout<<"指针"<<ptr<<"在栈中"<<endl; } else { cout<<"指针"<<ptr<<"不在栈中"<<endl; } } void test() { int i=0; ptr_in_stack(&i); int array[10000]; ptr_in_stack(&array[10]); int *p = new int; ptr_in_stack(p); } int main() { int i; stack_bottom = &i; //记录栈底位置,不是很精确 test(); return 0; }
------解决方案--------------------
Move effective C++ 里面专门有讲过这个问题,基本上没有可移植的方法来判断一个对象到底实在栈上还是在堆上。
不过书上也提出了一个解决办法,那就是重载operator new 和 operator delete函数,在operator new中将所有分配的
得到的指针放入一个链表,当调用operator delete时查看需要delete的指针是否存在与链表中,如果不在则表示当前delete
的指针不是有operator new分配的。
- C/C++ code
//.h class HeapTracked { // 混合类; 跟踪 public: // 从operator new返回的ptr class MissingAddress{}; // 异常类,见下面代码 virtual ~HeapTracked() = 0; static void *operator new(size_t size);//重载operator new 和operator delete static void operator delete(void *ptr); bool isOnHeap() const; private: typedef const void* RawAddress; static list<RawAddress> addresses; }; //.cpp // mandatory definition of static class member list<RawAddress> HeapTracked::addresses; // HeapTracked的析构函数是纯虚函数,使得该类变为抽象类。 // (参见Effective C++条款14). 然而析构函数必须被定义, //所以我们做了一个空定义。 HeapTracked::~HeapTracked() {} void * HeapTracked::operator new(size_t size) { void *memPtr = ::operator new(size); // 获得内存 addresses.push_front(memPtr); // 把地址放到list的前端 return memPtr; } void HeapTracked::operator delete(void *ptr) { //得到一个 "iterator",用来识别list元素包含的ptr; //有关细节参见条款35 list<RawAddress>::iterator it = find(addresses.begin(), addresses.end(), ptr); if (it != addresses.end()) { // 如果发现一个元素 addresses.erase(it); // 则删除该元素 ::operator delete(ptr); // 释放内存 } else { // 否则 throw MissingAddress(); // ptr就不是用operator new } // 分配的,所以抛出一个异常 } bool HeapTracked::isOnHeap() const { // 得到一个指针,指向*this占据的内存空间的起始处, // 有关细节参见下面的讨论 const void *rawAddress = dynamic_cast<const void*>(this); // 在operator new返回的地址list中查到指针 list<RawAddress>::iterator it = find(addresses.begin(), addresses.end(), rawAddress); return it != addresses.end(); // 返回it是否被找到 }
------解决方案--------------------
理论上说,特定在win32平台上,还是有办法检验指针是否是分配在堆上的。
因为malloc内部是调用HeapAlloc的,因此只要取得相应的指针的handle就可以直接调用win32 API的HeapValidate函数来判断该指针是否是在堆上。
至于如何从指针取得handle的方法,我没有在库函数中找到,这个可能是跟库相关的。