动态更改/选择类成员变量的类型

时间:2019-06-18 04:12:58

标签: c++ polymorphism containers

所以我对C ++真的很生疏,并且正在尝试实现一个紧凑的映射容器作为练习。我试图找出让我的班级为动态分配的数组选择最佳/最小类型的最佳方法。此外,这种类型可能会在对象的生命周期内发生变化。

想法是将哈希表分解为表和数据:

table: [-1, -1, 2, -1, 1, 0]

data: [ [h0, key0, value0], [h1, key1, value1], [h2, key2, value2] ]

在执行查找时,您对键%表大小进行哈希处理,并在数据数组中获取相应的索引。通过保持实际的哈希表稀疏且尽可能小和轻巧,可以获得良好的缓存速度等。此外,可以按顺序迭代元素。

为了使表较小,我希望它使用尽可能小的数据类型来保存索引(具有最大的余量以最大程度地减少冲突):

  • 最多可容纳127个项目
  • 短路到2 ** 15
  • 最多2 ** 31
  • 之后很久

随着添加更多条目,表数组将需要调整大小并最终更改类型。我正在尝试找出在容器中执行此操作的最佳方法。

由于我将不得不在定义中使用表数组类型,因此我将不得不使用某种多态性。我认为模板不会起作用,因为类型可以更改并且在运行时不会被知道。

我已经阅读了一些有关联合和变体的信息,但据我了解,它们并不起作用。

我有点C的知识,但是我知道在C ++中,使用void指针的想法很普遍。

我想出的最好的方法是告诉我的容器table数组都支持相同的接口。但是似乎我要复制很多代码,并为我想尽可能简单和快速地插入一些虚函数查找。


template <typename K, typename V>
struct Entry {
    int hash;
    V value;
    K key;
};

class Table {
    public:
        virtual int operator[](int) =0;
}

class CharTable: public Table {
    public:
        CharTable(int s) :t{new char[s]}{}
        int operator[](int i) { return t[i]; }
        ~CharTable() {delete t[];}
    private:
        char* t;
}

// short table etc...

template <typename K, typename V>
class CompactMapping {
    public:
        CompactMapping();
        V& operator[](const K&);
        unsigned int size() const {return sz;}
        void resize(unsigned int);
    private:
        vector<Entry<K,V>> entries;
        unsigned int sz;
        Table* table;
        int allocated;
}

template <typename K, typename V>
V& CompactMapping<K, V>::operator[](const K& key){
    //simplified
    int index = table[hash(key) % allocated];
    if (entries[index].key == key){
        return entries[index].value;
    }
}

template <typename K, typename V>
void CompactMapping<K, V>::resize(unsigned int s){
    if (s <= 2**7)
        CharTable* t = new CharTable(s);
    if (s <= 2**15)
        ShortTable* t = new ShortTable(s);
    //... maybe a switch statement instead

    for (int i=0; i!=sz; ++i)
        t[entries[i].hash %s] = i;
    delete *table;
    table = t;
    allocated = s;    
}

完整披露我实际上并未对此进行测试,因此可能无法实现。我只是想知道在我走这条路之前,我的想法是否还可以,或者是否有更好的解决方案。

我也很感谢你们能给我其他建议。

1 个答案:

答案 0 :(得分:1)

class CharTable: public Table

您可能想要这个:

template <class Index> class TypedTable : publlic Table { ... };
using CharTable = TypedTable<unsigned char>; // etc

这消除了代码重复。

现在使用虚拟呼叫不会使实现赢得任何速度竞争,但您应该首先进行概要分析。如果虚拟通话存在重大瓶颈,请尝试使用例如switch语句,看看是否有帮助。使用void指针是相对良性的,因为它仅限于严格控制的代码段。或者,您可以使用std::variant或您自己的带标记联合的实现。