【问题标题】:Object allocation on stack or heap堆栈或堆上的对象分配
【发布时间】:2013-01-25 16:48:04
【问题描述】:

我正在尝试建立一种机制来判断类对象的分配位置。 考虑在类中创建一个标志,但无法设置值,因为在“new”运算符的调用期间对象的生命周期没有开始。 在 C++ 中是否可以判断一个对象是在堆栈上还是在堆上(运行时)?

【问题讨论】:

  • 你需要它做什么?
  • 不能以任何便携方式。
  • 嗯,你可以嗅探周围的汇编指令,就像 Apple 在 Objective-C 运行时所做的那样。
  • 可以改类界面吗?它仍然必须可以从类继承吗?即使类实例是作为另一个类的一部分创建的,您是否希望它能够工作?

标签: c++ object runtime heap-memory stack-memory


【解决方案1】:

没有可移植的方式来执行此操作,但如果我们假设您要执行此操作的系统类型数量有限,您可以尝试以下方法:

获取 main 中某个局部变量的地址(或其他“调用堆栈中的低位”)。将其存储在全局变量中,让我们调用char *stackbase;

然后在你要签入的函数中获取一个局部变量的地址,我们称之为char *stacktop;

现在,如果我们有一个char *obj = reinterpret_cast<char *>(object_in_test);,那么:

if (obj > stacktop && obj < stackbase) on_stack = true;
else on_stack = false; 

请注意,这里有几个缺陷:

  1. 这是技术上未定义的行为。它适用于大多数系统,因为整个内存空间是连续的。但是在某些系统中,堆栈和内存的其他部分具有单独的“地址空间”,这意味着指向不同类型内存的两个指针可以具有相同的地址。
  2. 线程需要有一个“每线程堆栈库”。
  3. 假定堆栈“向零增长”(如果不是,则必须在 if 中反转 &gt;&lt;
  4. 全局变量将被视为not on stack
  5. 使用风险自负!

尽管有以下免责声明,但我完全希望必须删除此答案,因为它会被语言律师否决。

【讨论】:

    【解决方案2】:

    我一直在做一些实验,并发现这似乎可以在运行时判断一个对象是否在堆栈上分配。

    界面如下:

    #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
    

    而实现是:

    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;
    

    这似乎总是正常工作。对于在堆上分配的数组,条目的索引也是可用的。对于在堆栈上分配的值,或者对于仅单独分配的条目,get_heap_array_index() 函数返回 -1。

    此代码的假设是在任何给定线程上构造之前立即调用 new 运算符。然而,这个假设似乎适用于我尝试过的所有事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-21
      • 2020-08-24
      • 2020-03-30
      • 2018-09-09
      • 2017-03-25
      • 2014-05-30
      • 1970-01-01
      相关资源
      最近更新 更多