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;
}