我正在尝试建立一种机制来判断类对象的分配位置。考虑在类中创建一个标志,但无法设置值,因为在“new”运算符的调用期间对象的生命周期没有开始。在 C++ 中是否可以判断一个对象是在堆栈上还是在堆上(运行时)?
问问题
362 次
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;
请注意,这有几个缺陷:
- 这是技术上未定义的行为。它适用于大多数系统,因为整个内存空间是连续的。但是在某些系统中,堆栈和内存的其他部分具有单独的“地址空间”,这意味着指向不同类型内存的两个指针可以具有相同的地址。
- 线程需要有一个“每线程堆栈库”。
- 假设堆栈“向零增长”(如果不是,则必须反转 if 中的
>
and<
。 - 全局变量将被视为
not on stack
。 - 使用风险自负!
尽管有以下免责声明,我完全希望必须删除这个答案,因为它会被语言律师否决。
于 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 回答