Detecting stack or heap allocation
I have a class I'd like to be able to set a flag in that says if it is heap allocated so it can properly clean up after itself and not try to delete itself if it's on the stack. The problem is...I can't seem to override both new
and the constructors at the same time. So it goes from my new
overload that sets the isHeapAllocated
flag and then into my constructor which resets the flag.
void* String8::operator new(size_t size)
{
String8* string = (String8*)malloc(size);
if(string == null)
Exception("allocation fail : no free memory");
string->isHeapAllocated = true;
return string;
}
String8::String8()
{
isHeapAllocated = false;
}
So new String8()
sets the isHeapAllocated
flag and then resets it to false
. Is there any way to do this?
It will not work as intended:
The new operator return unitialized memory to be given to the constructor. You -correctly- do String8* string = (String8*)malloc(size);
, but *string
, at this stage is not yet a String8 object: it is just the memory bulk that will contain it.
So string->isHeapAllocated = true;
in fact sets a flag inside a not yet constructed object (that's UB).
Admitting this will not compromise the OS process, so that the program will not crash (you write memory that belongs already to you, after all ...), when you will later do something like String8* ptr = new String8;
, after new returns, the String8::String8 constructor is called, and the member will be set back to "false" independently on what you did in the new operator overload.
The idiomatic way to manage C++ objects is let who allocate to be responsible to deallocate. (and if "who" it is the stack, it just do that by definition).
This is a bad idea, but here's a way to do it that doesn't invoke undefined behaviour.
#include <iostream>
#include <memory>
#include <set>
using namespace std;
class C {
public:
void* operator new(size_t size) {
C* c = static_cast<C*>(::operator new(size));
heap_instances.insert(c);
return c;
}
C() : heap_allocated(heap_instances.find(this) != heap_instances.end()) {}
const bool heap_allocated;
private:
static set<const C*> heap_instances;
};
set<const C*> C::heap_instances;
int main(int argc, char** argv) {
cout << boolalpha;
C stack;
cout << stack.heap_allocated << 'n'; // false
C* heap_nozero = new C;
cout << heap_nozero->heap_allocated << 'n'; // true
delete heap_nozero;
C* heap_zero = new C();
cout << heap_zero->heap_allocated << 'n'; // true
delete heap_zero;
}
You can remove pointers from heap_instances
when you're done with them, of course, and use a more suitable container if you're running in a multithreaded environment. But again, I wouldn't recommend that you actually do this—deciding behaviour based on allocation is not something an object ought to do.
The only legitimate reason I can think of for this is to enable delete this
. While that's safe if you're careful not to access members after the object's suicide, it's usually saner to let objects manage the lifetimes of other objects.
Note that the construtor gets called if it is allocated on the stack or the heap and there is no way for the object to detect if it was allocated on the stack or in the heap.
To create an object at the stack you don't use any memory allocation functions like this
String8 myString;
To create it on the heap you do
String8 *myString = new String8();
note that you do have to do the cleanup manually after not using the object anymore.
For the use of Heap objects bound to stack scope you can check out the RAII principle which is used intensly by c++ programs (see here for a better explaination of the difference of heap allocation and stack allocation).
链接地址: http://www.djcxy.com/p/96546.html上一篇: C ++新的运营商范围
下一篇: 检测堆栈或堆分配