C ++ - 隐藏客户端代码中的模板参数

时间:2014-01-30 18:36:03

标签: c++ templates pointers memory-management

我最近一直在阅读关于c ++的自定义内存分配器,并且遇到了一个非常有用的概念,而不是使用指针“handle”,它们实际上是指针的指针,这允许分配器重新安排其内存以避免碎片,同时避免使所有指向已分配内存的指针无效的问题。

但是,不同的分配器可能希望以不同的方式使用句柄,例如池分配器不需要重新排列其内存,而其他分配器也是如此。那些需要重新排列内存的人可能需要将句柄视为指针指针,指针数组的索引等,而不重新排列内存的分配器会将句柄视为简单指针。理想情况下,每个分配器都能够使用不同类型的句柄,以便它可以实现最佳性能,具有虚拟方法的基本句柄类会产生大量开销,因为每次需要访问任何函数/成员时都会使用句柄动态分配的类。

我的解决方案是使用部分模板特化,以便在编译时解决句柄类型,消除虚拟机的运行时开销并允许编译器进行其他优化(例如:内联)

/////////////////////////////////////////////////
/// \brief The basic handle class, acts as simple pointer
/// Single layer of indirection
/////////////////////////////////////////////////
template <typename T>
class Handle{
public:
    T* operator->(){return obj;}
    //other methods...
private:
    T* obj;
};

/////////////////////////////////////////////////
/// \brief Pointer specialization of the handle class, acts as a pointer to pointer
/// allowing allocators to rearrange their data
/////////////////////////////////////////////////
template <typename T>
class Handle<T *>{
public:
    T* operator->(){return *obj;};
    //other methods...
private:
    T** obj;
};

这非常有效并且允许分配器返回它们需要的任何句柄类型,但是这意味着任何需要将句柄作为参数的函数都需要重载以接受这两种类型的特化,也就是一个持有句柄的类一个成员需要模板化它是否有一个普通的句柄,指针指针或其他类型的指针。

这个问题只会随着添加更多句柄类型或函数需要多个句柄而变得更糟,并且必须为句柄类型的所有组合提供过载。

要么我需要能够使指向“TypeA”实例的所有句柄都具有类型Handle<TypeA>,然后使用不同的方法来模板特化以提供不同的功能或以某种方式隐藏模板参数从使用句柄的任何代码。怎么可以实现呢?

(这种隐藏模板参数的方法在其他实例中也很有用,例如在policy based logging system中,类可能希望保留对任何类型的记录器的引用,而不需要模板化。显然,在这种情况下记录虚拟继承可以用作速度的主导因素是I / O而不是函数调用开销)

1 个答案:

答案 0 :(得分:3)

我已经实现了一个内存系统,它允许你描述的内容,但是如果没有虚函数就无法想到拥有唯一句柄类型的方法。模板参数是该类型的一部分。

最后,我创建了一个句柄类型,并使用指针的最低位来存储它是直接指针还是间接指针。在解除引用之前我会检查该位,如果没有设置,我只会返回指针,否则我会取消该位并向内存系统询问实际指针。

该方案确实有效但我最终从我的内存系统中删除了间接内存句柄支持,因为我发现开销可能非常高,因为它对我的代码的所有方面都是如此具有侵入性。基本上几乎每个地方都会使用一个指针,我不得不使用一个手柄。它还要求在使用其他线程之前锁定内存,以便在使用时不对其进行碎片整理。最后,它要求我完全自定义容器,以获得可接受的性能。例如,我不想在循环中对向量的每次访问进行双重间接。