How could I know if a pointer is on the stack or on heap?!
(How could I know if a pointer was allocated with new or with a reference?)
Printable View
How could I know if a pointer is on the stack or on heap?!
(How could I know if a pointer was allocated with new or with a reference?)
Although I don't understand why you would need to know this, as unless you are receiving a pointer from a function that you did not write, you should know if the data pointed at by the pointer is on the stack or the heap.
Why would you need to know?
it's simple!
call _msize. if it return 0 or something like that - object in stack!
Note. It's a Microsoft specific.
When compiled for debug, _msize() produces an ASSERT if the object was not allocated with malloc() family of functions.
James,
I believe you mean an address operator - not a reference.Quote:
(How could I know if a pointer was allocated with new or with a reference?)
That being said, I don't know any generic way you can tell whether a
pointer contains an address to stack or heap memory.
regards, willchop
There is no generic C++ way to do this. This is covered in one of Scott Meyer's Effective C++ books (Effective C++ or More Effective C++, I don't remember which one).
Since C++ doesn't assume that there is even a "stack", the answer to your question is highly system, compiler, and OS dependent.
Regards,
Paul McKenzie
I didn't post this question.
Not a big deal - but you typed James, and then quoted the poster of the question.
Sorry James!
-willchop
This function appears to only keep track of the actualQuote:
it's simple!
call _msize. if it return 0 or something like that
pointer to the memory allocated by malloc - not valid addresses
within that block. For this reason the function may not provide
accurate results.
For example:
The mid_buffer is pointing to memory that was dynamicallyCode:char* buffer = static_cast<char*>(malloc(1000 * sizeof(char)));
if (!buffer) return;
char* mid_buffer = buffer + 499;
printf("sizeof buffer: %d\n", _msize(buffer));
printf("sizeof mid_buffer: %d\n", _msize(mid_buffer));
free(buffer);
allocated, but _msize() fails to report so.
regards, willchop
You could either create a new operator for the specific object you want to check, or if it's for multiple objects, you could over write the global new operator.Quote:
(How could I know if a pointer was allocated with new or with a reference?)
Within your new operator, you can update a global vector of pointers, and then LATER, check the vector to see if your pointer is listed in the vector.
Here's an example:
#include <iterator>
#include <new>
#include <map>
class foo {
public:
int x;
void* operator new(size_t)
{
foo* ptr = ::new foo;
FooPtrs[ptr] = 0;
return ptr;
}
void operator delete(void* ptr)
{
FooPtrs.erase((foo*)ptr);
::delete ptr;
}
void* operator new[] (size_t s)
{
foo* ptr = ::new foo[s];
for(foo* p = ptr;p < ptr+s;++p)
FooPtrs[p]=s;
return ptr;
}
void operator delete[] (void* ptr)
{
size_t s = FooPtrs[(foo*)ptr];
for(foo* p = (foo*)ptr;p < (foo*)ptr+s;++p)
FooPtrs.erase(p);
}
static std::map<const foo*, size_t> FooPtrs;
static bool IsCreatedByNew(const foo* ptr)
{
return (FooPtrs.find(ptr) != FooPtrs.end());
}
};
std::map<const foo*, size_t> foo::FooPtrs;
int main(int argc, char* argv[])
{
foo *pXa = new foo[5];
foo *pX = new foo;
foo NotPtr;
foo NotPtrA[5];
bool t1 = foo::IsCreatedByNew(pXa);
pXa++;
bool t2 = foo::IsCreatedByNew(pXa++);
bool t3 = foo::IsCreatedByNew(pX);
bool t4 = foo::IsCreatedByNew(&NotPtr);
bool t5 = foo::IsCreatedByNew(&NotPtrA[0]);
bool t6 = foo::IsCreatedByNew(&NotPtrA[2]);
delete [] pXa;
delete pX;
bool t7 = foo::IsCreatedByNew(pX);
bool t8 = foo::IsCreatedByNew(pXa++);
return 0;
}
Correction:
Code:#include <iterator>
#include <new>
#include <map>
class foo {
public:
void* operator new(size_t)
{
foo* ptr = ::new foo;
FooPtrs[ptr] = 0;
return ptr;
}
void operator delete(void* ptr)
{
FooPtrs.erase((foo*)ptr);
::delete ptr;
}
void* operator new[] (size_t s)
{
foo* ptr = ::new foo[s];
for(foo* p = ptr;p < ptr+s;++p)
FooPtrs[p]=s;
return ptr;
}
void operator delete[] (void* ptr)
{
size_t s = FooPtrs[(foo*)ptr];
for(foo* p = (foo*)ptr;p < (foo*)ptr+s;++p)
FooPtrs.erase(p);
}
static std::map<const foo*, size_t> FooPtrs;
static bool IsCreatedByNew(const foo* ptr)
{
return (FooPtrs.find(ptr) != FooPtrs.end());
}
};
std::map<const foo*, size_t> foo::FooPtrs;
int main(int, char**)
{
foo *pXa = new foo[5];
foo *pX = new foo;
foo NotPtr;
foo NotPtrA[5];
bool t1 = foo::IsCreatedByNew(pXa);
pXa++;
bool t2 = foo::IsCreatedByNew(pXa++);
bool t3 = foo::IsCreatedByNew(pX);
bool t4 = foo::IsCreatedByNew(&NotPtr);
bool t5 = foo::IsCreatedByNew(&NotPtrA[0]);
bool t6 = foo::IsCreatedByNew(&NotPtrA[2]);
delete [] pXa;
delete pX;
bool t7 = foo::IsCreatedByNew(pX);
bool t8 = foo::IsCreatedByNew(pXa++);
return 0;
}
thank you all
Thanx...It works!
How about a generic method? a template seems to be more accurate here...
I hope the compiler is smart enough not to call the constructor twice.Quote:
Originally posted by Axter
Correction:
Code:void* operator new(size_t)
{
foo* ptr = ::new foo;
FooPtrs[ptr] = 0;
return ptr;
}
First of all, you don't check if calling global new fails or not. But in this case, it's not safe to do what this overload of new does. If global new succeeds - the constructor is called for the object. This could be disastrous if the class allocates memory in it's default constructor. Because when the overloaded new returns and succeeded - it's calls the constructor again. As you know, the constructor is the first function called in an object's life - therefore the member variable (the pointer) that points at memory is thought of as 'garbage' by the 2nd call to the constructor. Therefore you have a memory leak.
You're absolutely right. I assume the constructor would be called only when the global operator is called.Quote:
If global new succeeds - the constructor is called for the object. This could be disastrous if the class allocates memory in it's default constructor. Because when the overloaded new returns and succeeded - it's calls the constructor again. As you know, the constructor is the first function called in an object's life - therefore the member variable (the pointer) that points at memory is thought of as 'garbage' by the 2nd call to the constructor. Therefore you have a memory leak.
I modified the code to use malloc and free instead. That will prevent the double constructor and double destructor calls.
As this is just an example, I leave it up to the questioner to add extra required validation.
Code:#include <iostream>
#include <iterator>
#include <new>
#include <map>
#include <stdlib.h>
class foo {
public:
foo()
{
++Qty;
std::cout << "Passing through constructor " << Qty << std::endl;
}
~foo()
{
--Qty;
std::cout << "Passing through destructor " << Qty << std::endl;
}
void* operator new(size_t)
{
foo* ptr = (foo*)malloc(sizeof(foo));
FooPtrs[ptr] = 0;
return ptr;
}
void operator delete(void* ptr)
{
FooPtrs.erase((foo*)ptr);
free(ptr);
}
void* operator new[] (size_t s)
{
foo* ptr = (foo*)malloc(sizeof(foo)*s);
for(foo* p = ptr;p < ptr+s;++p)
FooPtrs[p]=s;
return ptr;
}
void operator delete[] (void* ptr)
{
free(ptr);
size_t s = FooPtrs[(foo*)ptr];
for(foo* p = (foo*)ptr;p < (foo*)ptr+s;++p)
FooPtrs.erase(p);
}
static std::map<const foo*, size_t> FooPtrs;
static bool IsCreatedByNew(const foo* ptr)
{
return (FooPtrs.find(ptr) != FooPtrs.end());
}
static int Qty;
};
int foo::Qty = 0;
std::map<const foo*, size_t> foo::FooPtrs;
void SomeFunction()
{
foo *pX = new foo;
foo *pXa = new foo[5];
foo NotPtr;
foo NotPtrA[5];
bool t1 = foo::IsCreatedByNew(pXa);
pXa++;
bool t2 = foo::IsCreatedByNew(pXa++);
bool t3 = foo::IsCreatedByNew(pX);
bool t4 = foo::IsCreatedByNew(&NotPtr);
bool t5 = foo::IsCreatedByNew(&NotPtrA[0]);
bool t6 = foo::IsCreatedByNew(&NotPtrA[2]);
delete pX;
pXa--;
pXa--;
delete [] pXa;
bool t7 = foo::IsCreatedByNew(pX);
bool t8 = foo::IsCreatedByNew(pXa++);
}
int main(int, char**)
{
SomeFunction();
return 0;
}
You can make the code more generic by having the new and delete operators call a global function that would update the Ptr map, and create/free memory.Quote:
How about a generic method? a template seems to be more accurate here...
The following is an example using some template functions.
Code:std::map<const void*, size_t> PtrTracker;
template<typename T>
T* GetTrackerMemory(size_t s)
{
T* ptr = (T*)malloc(sizeof(T)*s);
PtrTracker[ptr] = s;
return ptr;
}
template<typename T>
void FreeTrackerMemory(T* ptr)
{
size_t s = PtrTracker[ptr];
for(T* p = ptr;p < ptr+s;++p)
PtrTracker.erase(p);
free(ptr);
}
template<typename T>
bool IsCreatedByNew(const T* ptr)
{
return (PtrTracker.find(ptr) != PtrTracker.end());
}
class foo {
public:
foo()
{
++Qty;
std::cout << "Passing through constructor " << Qty << std::endl;
}
~foo()
{
--Qty;
std::cout << "Passing through destructor " << Qty << std::endl;
}
void* operator new(size_t)
{
return GetTrackerMemory<foo>(1);
}
void operator delete(void* ptr)
{
FreeTrackerMemory((foo*)ptr);
}
void* operator new[] (size_t s)
{
return GetTrackerMemory<foo>(s);
}
void operator delete[] (void* ptr)
{
FreeTrackerMemory((foo*)ptr);
}
static int Qty;
};
int foo::Qty = 0;
void SomeFunction()
{
foo *pX = new foo;
foo *pXa = new foo[5];
foo NotPtr;
foo NotPtrA[5];
bool t1 = IsCreatedByNew(pXa);
pXa++;
bool t2 = IsCreatedByNew(pXa++);
bool t3 = IsCreatedByNew(pX);
bool t4 = IsCreatedByNew(&NotPtr);
bool t5 = IsCreatedByNew(&NotPtrA[0]);
bool t6 = IsCreatedByNew(&NotPtrA[2]);
delete pX;
pXa--;
pXa--;
delete [] pXa;
bool t7 = IsCreatedByNew(pX);
bool t8 = IsCreatedByNew(pXa++);
}
int main(int, char**)
{
SomeFunction();
return 0;
}
Thank you a lot Axter for your effort.
It's only 1 problem....your code is not so generic...
Why?? If you have more classes ( let's suppose foo2, foo3, foo4 ......) you must modify each of them in order to find out whether an instance of any class is allocated on the heap or not...Am I wrong?
Here is the way a user would be happy to use...
Heap_Test<foo> pXa = new foo[5];
Heap_Test<foo1> pX = new foo;
Heap_Test<foo2> NotPtr;
Heap_Test<foo3> NotPtrA[5];
bool t1 = ::IsCreatedByNew(pXa);
bool t3 = ::IsCreatedByNew(pX);
bool t4 = ::IsCreatedByNew(NotPtr);
bool t5 = ::IsCreatedByNew(NotPtrA[0]);
bool t6 = ::IsCreatedByNew(NotPtrA[2]);
delete [] pXa;
delete pX;
bool t7 = ::IsCreatedByNew(pX);
I think above method involves smart pointers/handle...Unfortunately I cant implement it right now...I hope you will do Axter...
it might be some other better technics...
"If you want to supply an allocator/deallocator pair that works corectly for derived classes you must either supply a virtual destructor in base class or refrain from using the size t in deallocator"
B. Stroustrup "The C++ Programming Language", 3rd edition,
15.6 Free Store
Howdy Vije!
It is not clear why you want to discriminate between stack and heap allocated variables. Try the code below; it may help you.
Regards,Code:class B
{
private: ~B() {}
public: void release() { delete this; } // always on the heap
};
int main()
{
B* hb = new B; // ok
B sb; // error: destructor not visible
// ...
return 0;
}