Can a C++ class determine whether it's on the

2019-01-22 07:01发布

I have

class Foo {
....
}

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

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

and

function blah() {
  Foo foo* = new Foo(); // on the heap
}

I want Foo to be able to do different things depending on whether it's allocated on the Stack or the Heap.

Edit:

Alof of people have asked me "why do this?"

The answer:

I'm using a ref-counted GC right now. However, I want to have ability to run mark & sweep too. For this, I need to tag a set of "root" pointers -- these are the pointers on the stack. Thus, for each class, I'd like to know whether they're in the stack or in the heap.

标签: c++ stack heap
15条回答
成全新的幸福
2楼-- · 2019-01-22 07:17

There is a solution, but it forces inheritance. See Meyers, "More Effective C++", Item 27.

(You can see it in this link:
http://bin-login.name/ftp/pub/docs/programming_languages/cpp/cffective_cpp/MEC/MI27_FR.HTM)

查看更多
放荡不羁爱自由
3楼-- · 2019-01-22 07:19

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

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:

Apologies, you've probably found one of the few areas in which what you're asking makes sense. 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.
查看更多
劫难
4楼-- · 2019-01-22 07: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
查看更多
淡お忘
5楼-- · 2019-01-22 07:23

A hacky way to do it:

struct Detect {
   Detect() {
      int i;
      check(&i);
   }

private:
   void check(int *i) {
      int j;
      if ((i < &j) == ((void*)this < (void*)&j))
         std::cout << "Stack" << std::endl;
      else
         std::cout << "Heap" << std::endl;
   }
};

If the object was created on the stack it must live somewhere in the direction of the outer functions stack variables. The heap usually grows from the other side, so that stack and heap would meet somewhere in the middle.

(There are for sure systems where this wouldn't work)

查看更多
做个烂人
6楼-- · 2019-01-22 07:26

Overload new() for your class. This way you'll be able to tell between heap and stack allocation, but not between stack and static/global.

查看更多
再贱就再见
7楼-- · 2019-01-22 07:28

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.

查看更多
登录 后发表回答