C++类可以确定它是在堆栈还是堆上?

ano*_*non 37 c++ heap stack

我有

class Foo {
....
}
Run Code Online (Sandbox Code Playgroud)

有没有办法让Foo能够分开:

function blah() {
  Foo foo; // on the stack
}
Run Code Online (Sandbox Code Playgroud)

function blah() {
  Foo foo* = new Foo(); // on the heap
}
Run Code Online (Sandbox Code Playgroud)

我希望Foo能够做出不同的事情,这取决于它是在Stack上堆还是堆.

编辑:

Alof的人问我"为什么这样做?"

答案:

我现在正在使用重新计算的GC.但是,我希望能够运行标记和扫描.为此,我需要标记一组"根"指针 - 这些是堆栈上的指针.因此,对于每个类,我想知道它们是在堆栈中还是在堆中.

sth*_*sth 18

一种hacky方式:

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;
   }
};
Run Code Online (Sandbox Code Playgroud)

如果对象是在堆栈上创建的,那么它必须位于外部函数堆栈变量的方向上.堆通常从另一侧生长,因此堆栈和堆将在中间的某处相遇.

(确定系统不会起作用)

  • 我也相信他知道你知道他知道并且只是在说. (9认同)
  • 我没有测试它,但这可能不适用于多线程应用程序. (3认同)
  • 我实际上在 2003 年左右尝试过这个。不幸的是,它无法运行的系统之一几乎是任何打开优化的 C++ 编译器。 (2认同)

pax*_*blo 10

你需要真正问我们真正的问题:-)你很明白为什么你认为这是必要的,但几乎肯定不是.事实上,这几乎总是一个坏主意.

为什么你认为你需要这样做?

我经常发现这是因为开发人员想要根据分配的位置删除或不删除对象,但这通常应留给代码的客户端而不是代码本身.


更新:

道歉,你可能已经找到了你要问的几个领域之一.理想情况下,您将覆盖所有内存分配和取消分配运算符,以跟踪从堆中创建和删除的内容.

但是,我不确定拦截类的新/删除是一件简单的事情,因为可能存在delete未调用的情况,并且由于标记/扫描依赖于引用计数,因此您需要能够拦截指针赋值为了它正常工作.

你有没有想过如何处理这个问题?

经典的例子:

myobject *x = new xclass();
x = 0;
Run Code Online (Sandbox Code Playgroud)

不会导致删除调用.

另外,您将如何检测到指向某个实例的指针在堆栈中的事实?拦截new和delete可以让你存储对象本身是堆栈还是基于堆,但是我不知道你如何分辨指针的分配位置,特别是代码如:

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

  • 在用户标记/清除垃圾收集器中,我希望提供某种智能指针来包含指向可收集对象的指针(实际上,这提供了准确的标记).因此,您的代码段不合法,因为它们仅使用非gc原始指针引用gc对象."编译器 - 土地"实现可能使用保守标记并直接分析堆栈. (2认同)

Ter*_*fey 8

答案是否定的,没有标准/可移植的方式来做到这一点.涉及重载新操作员的黑客往往会有漏洞.依赖于检查指针地址的黑客是特定于操作系统和特定于堆的实现,并且可能随着操作系统的未来版本而改变.您可能对此感到满意,但我不会围绕此行为构建任何类型的系统.

我会开始寻找不同的方法来实现你的目标 - 或许你可以有一个完全不同的类型作为你的方案中的"根",或者要求用户(正确地)使用特殊的构造函数来注释堆栈分配的类型.


小智 8

如果将“this”的值与堆栈指针的当前值进行比较,则是可能的。如果这个 < sp 那么你已经在堆栈中分配了。

试试这个(在 x86-64 中使用 gcc):

#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;
}
Run Code Online (Sandbox Code Playgroud)

它应该输出:

Stack 
Heap 
Stack 
Stack 
Heap
Run Code Online (Sandbox Code Playgroud)


Mat*_*ner 5

一种更直接、侵入性更小的方法是在内存区域映射(例如/proc/<pid>/maps)中查找指针。每个线程都有一个分配给其堆栈的区域。静态和全局变量将位于.bss 段中,常量位于 rodata 或 const 段中,等等。