Sign in to follow this  
ClementLuminy

Determine if c++ Object are on stack or on heap ...

Recommended Posts

Hello. I have a problem with my smart pointer system: Suppose i create an object on the stack, and then, i reference this object using a smart pointer. When the object get out of scope it is automaticaly destroyed ( because it's on the stack ), but, my smart pointer is still pointing to it, and when the smart pointer get destroyed, it try do delete an object that do not exist anymore .... :( Since a few hours, i'm looking over the web, to find a way to determine if an object is on the stack or on the heap, but i didn't find any solution to this problem .... Do you ever encounter this problem??? Can you give me some clues on how to solve this problem ??? Thanks a lot !! Clement

Share this post


Link to post
Share on other sites
Well, it's probably possible to get the address of the bottom and top of the stack and check if the pointer is in this range. However, this is not the answer. The answer is that you should NEVER be pointing to a stack-allocated object using a smart pointer.

If you have a section of code that you know isn't going to be deleting an object, then there's no reason to reference the object via a smart pointer there - just use a normal pointer or a reference.

Share this post


Link to post
Share on other sites
You really, really don't want to do this, what would be the point? The solution is not to use smart pointers - its not what they were designed for. If you have to pass in a smart pointer, you need to allocate the object on the heap.

It sounds like you are trying to work around a design problem elsewhere in your system.

Share this post


Link to post
Share on other sites
The main problem is that you use a smart pointer (or any pointer for that matter) to reference an object that is on the stack. I would definitely recommend against this.

First of all, try to solve the problem without referencing a stack object with a pointer.

Next - if you insist on doing this, there are many (very ugly) things you can do. For example, you can have a flag in your smart pointer class, and you can set the object to be dynamic/static, therefore causing the smart ptr to release it (or not). This is just one possible course of action. There are many more ideas that can help you - but if you'll look into the design you'll find that the main problem is referencing a stack object with a smart pointer. If you want, you can tell us why do you need to do such a thing - and maybe someone will have a better idea for you.

Share this post


Link to post
Share on other sites
If your smart pointer implements the semantics of a weak pointer (become a null pointer when the referenced object is deleted to prevent a dangling pointer) then you are fine.

To distinguish between an object being on the stack vs. being on the heap you have two options:
1) Implement your own heap manager to know the address ranges of objects that were allocated on the heap. Your smart pointer can then check if the address its pointing to is within one of those ranges. (Note that you can delegate the actual work of memory management to new/delete.)
2) For every thread (each has its own stack) take the address when the thread is started. When your smart pointer needs to determine if the address its pointing to refers to the stack, it has to check if that address falls into the range between the marker and the current stack pointer for each thread.

Share this post


Link to post
Share on other sites
Unless your smart pointer class is utterly brain-dead, pointing to a stack object should not pose an problem implementation problem. Well-designed smart pointer classes such as boost::shared_ptr allow you to provide the destruction function (because you'd need it to differentiate new and malloc anyway).

The main problem here is a semantic one: the intended use of a (non-weak) smart pointer is to share ownership of the variable. However, a stack variable is owned by the scope it lives in, and that ownership cannot be shared. You can still make the assumption that the variable will not go out of scope while still in use:

T t;
{
boost::shared_ptr<T> p( &t, NOP() );

// ... use the smart pointer ...

assert (p.unique());
}


However, this is brittle and prone to errors even if tested thoroughly. It is best to simply allocate the object on the heap and delegate ownership to the smart pointer.

Share this post


Link to post
Share on other sites
I somehow miss the point of this.

How can you run into such situation in the first place?

Objects "allocated" on stack are completely different. While its constructor and destructor are called, the memory allocation is implied by the compiler.

Heap allocated objects are explicitly allocated by the user, and need to be de-allocated explicitly. So if you run into a situation like this it's likely a design issue.

I use stack allocated memory in network and messaging code. The dependant code gets these variables by const reference. This way, if the data needs to be modified it's necessary to copy it in the first place, and storing references is a tricky and unadvisable in the first place.

I'd strongly advise you to rethink your design if you run into such situation. I'd suggest passing objects by reference in the first place, and only use smart pointers for dynamically allocated objects.

The other is obviously to pass a flag to smart pointer to indicate whether it owns data or not. If not, the destructor will not attempt to de-allocate the data smart pointer points to.

I used the later technique in memory buffer design, but I ensure the data gets properly allocated/de-allocated with use of class design, where buffers can only be obtained in such a way that memory ownership issues don't arrise - these buffers deal with exactly such a problem. When serializing data, they use stack allocated buffer. If this buffer gets too small, bigger one is allocated on the heap. Buffers get passed around by const reference as well.

Share this post


Link to post
Share on other sites
Disregarding all the reasons why you shouldn't do this (Don't do this) there are platform specific ways to do this (Don't do this). In MSVC, _CrtIsValidHeapPointer will tell you if a pointer is into the heap or not (Don't do this) but it only works in debug.

Share this post


Link to post
Share on other sites
I understand, that it's not the purpose of smart pointer to point to stack allocated object.

But the thing is that now, i must create all "smart pointed" object on the heap, which is not relly a problem on it's own...
It's just that sometime it's more "simple" to let the stack system create and destroy the object...

Fo exemple, if i need to create a file object ( which is referenceable in my system ), in order to use it in a simple loading function, actually i must allocate it on the heap....

But it would be more convenient to be able to also use it as a stack allocated object ....

Anyway ...

I think i'm gonna use the _CrtIsValidHeapPointer in order to detect when a smart pointer try to point to a stack allocated object ( and assert when it's the caase ).....


Thanks for your help :)


Share this post


Link to post
Share on other sites
We need some phrase or image for when someone is given tons of good advice, and decides based on that advice to take the most idiotic possible route.

Share this post


Link to post
Share on other sites
Quote:

Fo exemple, if i need to create a file object ( which is referenceable in my system ), in order to use it in a simple loading function, actually i must allocate it on the heap....

But it would be more convenient to be able to also use it as a stack allocated object ....


Zero need whatsoever for determining heap or stack allocation.


void load( const File &f );

File f_stack;
File *f_heap = new File();
smart_ptr<File> f_smart;

load( f_stack );
load( *f_stack );
load( *f_smart );



You should be using references and stack allocated objects everywhere in the first place.

If you can't, and really can't, then use smart pointers.

The reason for this is two-fold. One - references cannot be null or invalid. Two - the life-cycle management is not available to function, which removes a lot of headaches about ownership.

Share this post


Link to post
Share on other sites
If you can prove that you ever need a smart pointer to an object on the stack then I'll help you get around the problem. Otherwise, simply don't do it!

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
We need some phrase or image for when someone is given tons of good advice, and decides based on that advice to take the most idiotic possible route.


You mean something like this?

Share this post


Link to post
Share on other sites
Okay okay ....

So after a few reflexion, here is in fact what i need:

I way to detect if a smart pointer is pointing to an object that is allocated on the stack, in order to do an assertion. ( To inform the user that it's not allowed to have a pointer point to a stack allocated object )

I have try with the CrtIsValidHeapMemory function, but it seam that i must make all my memroy allocation using crt_malloc, which is actually not the case ....
:(

Any idea ???

thanks again :)

Clement

Share this post


Link to post
Share on other sites
Override the global new/delete operators, keep track of who allocates what.

When a smart pointer is created, check to see if this memory was allocated. If it wasn't, it's on stack. That is of course assuming several things about memory allocations, but it's probably your best bet.

The other solution is to simply make the smart pointer oblivious to actual location of memory, and do what boost does, advise that proper usage is to only use smart pointers for dynamically allocated memory.

Third solution might be to look into how your compiler manages memory, then calculate whether the address provided is within stack or heap region.

The language itself doesn't deal with this. Those are all implementation and OS specific issues.

Share this post


Link to post
Share on other sites
Quote:

I way to detect if a smart pointer is pointing to an object that is allocated on the stack, in order to do an assertion. ( To inform the user that it's not allowed to have a pointer point to a stack allocated object )

This seems like a waste of time to me. You'll be going to a lot of effort to detect an edge case that arises from of a programmer intentionally attempting to subvert your API. The fact that you should not store pointers to stack-allocated objects for an indeterminate period of time should be something every minimally competent C++ programmer is aware of (similar to how you should never return pointer or references to stack-allocated local variables from functions).

It is folly to attempt to protect your code from intentional subversion by a programmer. You're only going to make more work for yourself and hamper the legit users of your API. I seriously would not bother.

Share this post


Link to post
Share on other sites
Here is a crazzy crazzy idea!
Read ESP register: (may be like this)

DWORD get_ESP()
{
DWORD rv;
__asm{ move rv,ESP};
return rv;
}
upper = get_ESP()& 0x FFFFF000;
if((unsigned long)&your_variable & 0xFFFFF000 == upper)
// yeah is on stack..



you may dig into this...

Share this post


Link to post
Share on other sites
Ew.

That is not a scalable technique, and it won't even work for all cases on one specific OS/CPU/etc, either (after all, what you technically need to be aware of are objects that were not allocated with new, not objects that are on the stack).

This is still a bad idea.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this