I'm trying to make a mechanism that could tell where the object of the class is allocated. Thought about making a flag in the class, but it's not possible to set a value because object's lifetime is not started during the call of "new" operator. Is it possible in C++ to tell if an object is on stack or heap (runtime)?
-
4What do you need it for? – Andy Prowl Feb 10 '13 at 12:22
-
1Not in any portable way. – juanchopanza Feb 10 '13 at 12:22
-
Well, you can sniff the surrounding assembly instructions, like Apple does in the Objective-C runtime. – Feb 10 '13 at 12:28
-
Can you change the class interface? Does it still have to be possible to inherit from the class? Do you expect this to work even if the class instance is created as part of another class? – David Schwartz Feb 10 '13 at 12:30
-
1possible duplicate of [Can a C++ class determine whether it's on the stack or heap?](http://stackoverflow.com/questions/2054710/can-a-c-class-determine-whether-its-on-the-stack-or-heap) – Bo Persson Feb 10 '13 at 12:35
2 Answers
There is no portable way to do this, but if we assume you have a limited amount of system types where you are going to do this on, you could try the following:
Take the address of some local variable in main (or other "low in the callstack"). Store this in a global variable, lets call char *stackbase;
Then take the address of a local variable in your function that you are checking in, let's call it char *stacktop;
Now, if we have a char *obj = reinterpret_cast<char *>(object_in_test);
, then:
if (obj > stacktop && obj < stackbase) on_stack = true;
else on_stack = false;
Note that there are SEVERAL flaws with this:
- It's technically undefined behaviour. It will work on most systems, because the whole memory space is contiguous. But there are systems where the stack and other sections of memory have separate "address spaces", which means that two pointers to different types of memory can have the same address.
- Threads will need to have a "per thread stackbase".
- The stack is assumed to "grow towards zero" (if not, you'll have to invert the
>
and<
in the if. - Global variables will be seen as
not on stack
. - USE AT YOUR OWN RISK!
I fully expect to have to delete this answer as it will be downvoted by language lawyers, despite the disclaimer below.

- 126,704
- 14
- 140
- 227
I have been doing some experimentation, and have discovered that this seems to work for being able to always tell at runtime if an object was allocated on the stack or not.
The interface is as follows:
#ifndef HEAPAWARE_H
#define HEAPAWARE_H
#include <cintttypes>
class HeapAware
{
public:
HeapAware();
void *operator new(std::size_t size);
void *operator new[](std::size_t size);
void operator delete(void *ptr, std::size_t);
void operator delete[](void *ptr, std::size_t);
bool is_on_heap() const { return on_heap; }
std::ptrdiff_t get_heap_array_index() const { return heap_array_index; }
private:
const bool on_heap;
const std::ptrdiff_t heap_array_index;
static thread_local HeapAware * last_alloc;
static thread_local std::size_t allocated_size;
};
#endif
And the implementation is:
void *HeapAware::operator new(std::size_t size)
{
auto result = last_alloc = reinterpret_cast<HeapAware*>(malloc(size));
allocated_size = 1;
return result;
}
void *HeapAware::operator new[](std::size_t size)
{
auto result = last_alloc = reinterpret_cast<HeapAware*>(malloc(size));
allocated_size = size;
return result;
}
void HeapAware::operator delete(void *ptr, std::size_t)
{
free(ptr);
}
void HeapAware::operator delete[](void *ptr, std::size_t)
{
free(ptr);
}
HeapAware::HeapAware():on_heap(this>=last_alloc && this<last_alloc+allocated_size),heap_array_index(allocated_size>1?this-last_alloc:-1)
{
}
thread_local HeapAware * HeapAware::last_alloc = nullptr;
thread_local std::size_t HeapAware::allocated_size = 0;
This seems to always work correctly. For arrays allocated on the heap, the index of the entry is also available. For values that are allocated on the stack, or for entries that are just allocated singly, the get_heap_array_index()
function returns -1.
The assumption that this code makes is that the new operator is called immediately before construction on any given thread. This assumption seems to hold true for everything I have tried, however.

- 2,638
- 2
- 22
- 54