Can a C++ class determine whether it's on the stack or heap?

后端 未结 15 2135
有刺的猬
有刺的猬 2020-12-13 04:14

I have

class Foo {
....
}

Is there a way for Foo to be able to separate out:

function blah() {
  Foo foo; // on the stack
         


        
相关标签:
15条回答
  • 2020-12-13 04:18

    Take a look at the program here: http://alumni.cs.ucr.edu/~saha/stuff/memaddr.html. With a few casts, it ouputs:

            Address of main: 0x401090
            Address of afunc: 0x401204
    Stack Locations:
            Stack level 1: address of stack_var: 0x28ac34
            Stack level 2: address of stack_var: 0x28ac14
            Start of alloca()'ed array: 0x28ac20
            End of alloca()'ed array: 0x28ac3f
    Data Locations:
            Address of data_var: 0x402000
    BSS Locations:
            Address of bss_var: 0x403000
    Heap Locations:
            Initial end of heap: 0x20050000
            New end of heap: 0x20050020
            Final end of heap: 0x20050010
    
    0 讨论(0)
  • 2020-12-13 04:19

    It is possible if you compare the value of 'this' with the current value of the stack pointer. If this < sp then you have been allocated in the stack.

    Try this out (using gcc in x86-64):

    #include <iostream>
    
    class A
    {
    public:
        A()
        {
            int x;
    
            asm("movq %1, %%rax;"
                "cmpq %%rsp, %%rax;"
                "jbe Heap;"
                "movl $1,%0;"
                "jmp Done;"
                "Heap:"
                "movl $0,%0;"
                "Done:"
                : "=r" (x)
                : "r" (this)
                );
    
            std::cout << ( x ? " Stack " : " Heap " )  << std::endl; 
        }
    };
    
    class B
    {
    private:
        A a;
    };
    
    int main()
    {
        A a;
        A *b = new A;
        A c;
        B x;
        B *y = new B;
        return 0;
    }
    

    It should output:

    Stack 
    Heap 
    Stack 
    Stack 
    Heap
    
    0 讨论(0)
  • 2020-12-13 04:19

    I would recommend using smart pointers instead. By design, the class should have data and information about class. Book-keeping tasks should be delegated outside the class.

    overloading new and delete can lead to more holes than you can imagine.

    0 讨论(0)
  • 2020-12-13 04:21

    Nope, it can't be done reliably or sensibly.

    You may be able to detect when an object is allocated with new by overloading new.

    But then what if the object is constructed as a class member, and the owning class is allocated on the heap?

    Here's a third code example to add to the two you've got:

    class blah {
      Foo foo; // on the stack? Heap? Depends on where the 'blah' is allocated.
    };
    

    What about static/global objects? How would you tell them apart from stack/heap ones?

    You could look at the address of the object, and use that to determine if it is within the range that defines the stack. But the stack may be resized at runtime.

    So really, the best answer is that "there's a reason why mark & sweep GC's aren't used with C++". If you want a proper garbage collector, use a different language, one which supports it.

    On the other hand, most experienced C++ programmers find that the need for a garbage collector pretty much vanishes when you learn the necessary techniques for resource management (RAII).

    0 讨论(0)
  • 2020-12-13 04:27

    The answer is no, there is no standard/portable way to do this. Hacks involving overloading the new operator tend to have holes. Hacks that depend on checking pointer addresses are OS specific and heap implementation specific, and may change with future versions of the OS. You may be comfortable with that, but I wouldn't build any sort of system around this behavior.

    I would start looking at different ways to accomplish your goal - perhaps you can have a totally different type to serve as the "root" in your scheme, or require the users to (properly) annotate the stack allocated types as such with a special constructor.

    0 讨论(0)
  • 2020-12-13 04:28

    You need to actually ask us the real question(a) :-) It may be apparent to you why you think this is necessary but it almost certainly isn't. In fact, it's almost always a bad idea. In other words, why do you think you need to do this?

    I usually find it's because developers want to delete or not delete the object based on where it was allocated but that's something that should usually be left to the client of your code rather than your code itself.


    Update:

    Now that you've clarified your reasons in the question, I apologise, you've probably found one of the few areas in which what you're asking makes sense (running your own garbage collection processes). Ideally, you'd override all the memory allocation and de-allocation operators to keep track of what is created and removed from the heap.

    However, I'm not sure it's a simple matter of intercepting the new/delete for the class since there could be situations where delete is not called and, since mark/sweep relies on a reference count, you need to be able to intercept pointer assignments for it to work correctly.

    Have you thought about how you're going to handle that?

    The classic example:

    myobject *x = new xclass();
    x = 0;
    

    will not result in a delete call.

    Also, how will you detect the fact that the pointer to one of your instances is on the stack? The interception of new and delete can let you store whether the object itself is stack or heap-based but I'm at a loss as to how you tell where the pointer is going to be assigned to, especially with code like:

    myobject *x1 = new xclass();  // yes, calls new.
    myobject *x2 = x;             // no, it doesn't.
    

    Perhaps you may want to look into C++'s smart pointers, which go a long way toward making manual memory management obsolete. Shared pointers on their own can still suffer from problems like circular dependencies but the judicious use of weak pointers can readily solve that.

    It may be that manual garbage collection is no longer required in your scenario.


    (a) This is known as the X/Y problem. Many times, people will ask a question that pre-supposes a class of solution whereas a better approach would be just to describe the problem with no preconceptions of what the best solution will be.

    0 讨论(0)
提交回复
热议问题