Re: Detecting pointer on the heap
* pfultz2:
I want detect if a pointer is pointing to memory on the heap or the
stack, so I came up with this approach:
bool isOnHeap(void * p)
{
int i = 0;
int * s = &i;
return (p > s);
}
I dont if this is the best or most portable way to do it. And im not
sure how well it works for static and global variables, do they start
on the end of memory? or at the begining? The reason why i want to do
this is need to delete pointers sometimes, and some of them point to
memory on the stack, so therefore i dont want to delete them, I could
use type erasure and create a seperate class to handle the memory and
use some form of custom deallocators, but then it would either cost me
an extra pointer or double dereferencing, and i was trying to think of
a neater way to do it. thanks.
Others have discussed partial solutions for various systems (mainly Windows).
The only comment I miss there is about the pointer pointing to an object that is a member of another object. Then the information that it's within some heap doesn't tell you that it should be deallocated on its own (it shouldn't). And so a function like 'isOnHeap' can only be a reliable guide to deallocation if the object is guaranteed to not be part of another object.
But even without that consideration the upshot is that it's generally impractical and unreliable to detect how an object was allocated. Instead, at the point where an object needs to be deallocated it should be known how to deallocate it. One way to do that is to endow each type T object with the necessary information, which as you note means some wasted bytes, and one much easier way is to limit how type T objects can be allocated, namely to limit it to only one kind of allocation: then how to deallocate is known.
C++ does not in general support any complete guarantees about anything; almost any scheme to guarantee something can be subverted.
Therefore, schemes to guarantee automatic allocation (stack, static) or dynamic allocation (commonly known as heap) are not tamper-proof. They only yield guarantees against *inadvertent* incorrect allocation. With that in mind...
- Guaranteeing dynamic allocation.
The FAQ's answer to the question of "guarantee heap allocation" is to limit access to constructors and define factory functions. For a class with n constructors this generally means defining n factory functions.
A much easier way is to limit access to the class' destructor and grant friendship to a single templated destruction function. I.e., instead of using custom factory functions that depend on the class, the client code instead uses a single well-known custom destruction function. And it's less to code.
In order to support inheritance the destructor should be made protected, not private.
In contrast to factory functions this does not guarantee that the memory for an object is allocated using a 'new' expression, say. Bad client code might use 'malloc' and a placement 'new', for example. But it's not a practical problem.
And on the upside, for m classes with on average n constructors each, the m*n factory functions have been replaced with a single destruction function.
- Guaranteeing non-dynamic allocation.
Preventing use of 'new' is a bit harder. But you can do it by limiting access to things that a 'new' expression uses, such as the allocation function 'operator new'. If so then also access to its cousin 'operator new[]' needs to be limited.
I've never done this because in practice it's a protection that's not needed. It would be like paying for a specially paint-sniffing-trained security guard to follow you around and make sure you don't sit down on any bench with still wet paint. It really doesn't happen often enough (if ever) to justify the expense.
However, a variation of this scheme can also be used to almost-guarantee that objects of type T are always handled by smart pointers of type SP. For this, instead of limiting access the allocation functions can be outfitted with an extra dummy argument of some special type in order to make 'new' expressions so hideously complicated that they can't be typed inadvertently. A single common factory function or macro can then be defined that goes through the necessary contortions to allocate a T object and wrap the pointer in an SP instance.
Cheers & hth.,
- Alf
Disclaimer: posting late at night, so, typos and/or thinkos may be present in the above, but essentially it's just a condensed version of the corresponding sections of my old (now unfortunately off-line) C++ pointers tutorial.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]