【问题标题】:Determine the type of a pointer确定指针的类型
【发布时间】:2016-08-21 16:50:11
【问题描述】:

所以我正在制作一个内存堆栈分配器,它能够以连续的方式将任何类型的任何实例分配到堆上。

为了做到这一点,我在每个分配之前直接添加了一个“AllocationHeader”类,其中包含实例地址本身的 void* 和前一个标头的 AllocationHeader*。 到目前为止,这工作得很好,我能够分配和解除分配等。

但我遇到了 1 个(可能是 2 个)问题。 为了正确解除分配,我还需要调用相关对象的析构函数,然后将其从堆栈中删除。 当我删除一个我有一个指针的实例时这很好,因为我可以将它传递给 deallocate 函数并且它知道它是什么类型并做它的事情。

问题出在我想创建像 deallocateAll() 或 deallocateAllAboveObject(T* obj) 这样的函数时,因为我需要知道每个分配的类型而不显式传递它们的指针,所以我可以向下堆栈中的每个分配边走边调用每个的解构器。

我想要的是能够创建一个 AllocationHeader 来存储任何类型的指针,然后可以在以后不知道类型的情况下检索指针的类型。

我真的不确定如何执行此操作,因为到目前为止我看到的所有建议都涉及将对象与特定类型进行比较并查看它们是否相同。但是,我不能只检查程序中每个可能的类,因为我继续在此基础上构建可能有 1000 个。

或者,如果您对可以处理任何类型的堆栈分配器的替代方法有任何建议,那也很好。

任何帮助都将不胜感激。

【问题讨论】:

  • 最好在这里发布您的代码而不是解释它
  • 您必须将每个对象的类型信息存储在某处,要么与数据一起存储,要么存储在单独的容器中,如std::map
  • @gdlmx 到目前为止,我还没有任何与这个问题相关的代码,甚至在我尝试创建一些东西之前,我尝试了一些计划并且知道我会遇到这个问题。我所知道的是我需要一个包含指向任何可能对象的指针的类,然后我可以以某种方式找出类中指针的类型。
  • @gdlmx 如果我将 type_info 存储在其他地方,我该如何使用它呢?我已经想到了这种方法,但我认为它不起作用,因为虽然 type_info 包含类型的信息,但我不能使用它来(例如)将 void* 转换为 MyClass* 而不进行某种类型的比较我拥有的 type_info 和 MyClass type_info。这是对的还是我弄错了?
  • type_info 我的意思是特定类型/类的 constructordestructor,如@Isaac 的答案所示。像std::unordered_map<void *, std::pair<func_ptr, func_ptr>> allocator 这样typedef void (*func_ptr)() 和对分别存储构造函数和析构函数指针。然后你可以通过allocator[p].second(p); 销毁对象

标签: c++ templates memory-management types allocator


【解决方案1】:

由于 C++ 的静态类型系统,我只能看到几个解决问题的方法

  • 让分配器使用的每个类型都派生自具有虚拟析构函数的(一致)类型,例如struct destructible { virtual ~destructible() { } },但是这可能会扩大和更改您更改为从中派生的任何类型的布局。

或者在分配存储一个执行销毁的函数对象,例如使用以下模板

template<typename T> void destroy(void* p) { reinterpret_cast<T*>(p)->T::~T(); }

struct AllocationHeader
{
    template<typename T> AllocationHeader(AllocationHeader* previouse, void* data)
        : previouse(previouse), data(data), destructor(&destroy<T>) { }
    AllocationHeader* previouse;
    void* data;
    void (*destructor)(void*);
}
void deallocateAll(AllocationHeader& start)
{
    for (AllocationHeader* a = &start; a != nullptr; a = start->previouse;)
    {
        a->destructor(a->data);
        delete a->data;
    }
}

(如果不提供AllocationHeader 类型的代码,很难为您提供帮助。)

注意:我的编译器/IDE目前正在重新安装,所以我无法测试上面的代码,我很确定大部分代码,除了我可能需要在析构函数调用语法reinterpret_cast&lt;T*&gt;(p).T::~T();中添加typename /p>

编辑使用模板构造函数,在模板参数不能被推断的情况下是个坏主意,应该使用下面的构造函数来代替

AllocationHeader(AllocationHeader* previouse, void* data, void(*destructor)(void*))
        : previouse(previouse), data(data), destructor(destructor) { }

只需将&amp;destroy&lt;T&gt; 作为第三个参数传递给它。

【讨论】:

  • 好吧,如果我理解正确的话 void()(void) 析构函数只是指向 T 类型析构函数的指针?
  • @LukeBourne 是的,但是我的语法是错误的(不幸的是,函数指针的 C/C++ 语法非常荒谬和令人困惑),应该是 void(*destructor)(void*)
  • 好的,我认为这确实有效! :) 我稍后会对其进行测试,但我认为这至少对于我当前的问题来说是一个很好的解决方案。谢谢。
  • 嘿,我遇到了死胡同。如何调用 AllocationHeader 上的构造函数来创建新标头? AllocationHeader* cHeader = new(address) AllocationHeader::AllocationHeader(lastAllocation, address);AllocationHeader* cHeader = new(address) AllocationHeader(lastAllocation, address); 产生错误:/
  • @Luke 什么错误?你也意识到代码会在'address'处用'data = this'构造一个新的AllocationHeader?好像有点奇怪……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
  • 2015-04-06
  • 2021-10-16
  • 2011-09-14
相关资源
最近更新 更多