1

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

4

2 回答 2

3

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

获取 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 中的>and <
  4. 全局变量将被视为not on stack
  5. 使用风险自负!

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

于 2013-02-10T12:32:23.940 回答
1

我一直在做一些实验,并且发现这似乎有助于在运行时始终判断对象是否在堆栈上分配。

界面如下:

#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 运算符。然而,这个假设似乎适用于我尝试过的所有事情。

于 2016-09-18T23:52:22.553 回答