From: Alf P. Steinbach on
* 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! ]

From: Falk Tannhäuser on
Am 04.04.2010 04:16, schrieb Alf P. Steinbach:
> 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.

In C++0x, thanks to perfect forwarding, this n will become 1.

Falk

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Öö Tiib on
On 4 apr, 05:16, "Alf P. Steinbach" <al...(a)start.no> wrote:
> 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.

Yes, it is certainly less to type. Note however that factory function
that returns proper pointer/handle type may solve other related issues
too. Objects are not only created or destroyed in wrong way at wrong
place but also accessed there, operated there and passed to there.

Examples of related problems:
* MS C++ GUI framework (MFC) is seemingly designed at era before
threads so you may have to take additional measures to pass (or block
passing) such GUI objects between threads.
* Windows Shared library (DLL) interface is with gotchas. You may have
to switch contexts to create, open, destruct, close or pass something
there (or at least block the operations in wrong context) to not
crash.
* OpenGL uses current thread ID to decide on what display you are
operating. You cannot just enwrap its usage behind usual classes/
interfaces or someone eventually misuses these.
* It is sometimes cumbersome to achieve basic exception safety without
smart pointers, but new returns raw pointers. It may be expensive to
leak (and latter looks better than former):

boost::shared_ptr< cosmos::Star > sun( new
cosmos::Star( params ) );
or:
cosmos::StarPtr sun = cosmos::createStar( params );

So, factory functions that may produce expected situation-aware
pointer/handle objects help on such common cases. Especially if you
can not rewrite parts of problem's source. Once present it raises
fewer questions even if it is used only for solving lesser concerns
(like for enforcing specific allocation type) on some other place.

> 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.

Yes, deliberately guarding against such hacks always surprises me.

> 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.

There must not be m*n factory functions, because uniform behavior is
important only for classes that the module exposes to other modules.
Locally within module it is within control of module author(s)
already. Further, if the module under question must be portable to
Windows as DLL you may have to do the factory functions in interface
anyway.

> - 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.


Yes, like you say it is overkill. Resemblance: Someone wanted to block
further inheritance of a class so badly that he did inherit it from a
dummy private virtual base class. 100% of readers had never seen such
a beast used before. More funny than private operator new[]:

#ifndef I_SWEAR_TO_NOT_ALLOCATE_ParticularClass_dynamically
# error "You may not use it!"
#endif



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]