如何使用未知(类似int)类型作为std :: vector的索引?

时间:2010-09-22 15:23:57

标签: c++ data-structures stl vector typedef

我正在使用我正在使用的代码的另一部分中定义的类型Id

typedef int Id;

现在我提供了许多对象,每个对象都带有这样的Id,我想使用Id作为存储这些对象的std::vector的索引。它可能看起来像这样:

std::vector<SomeObj*> vec(size);
std::pair<Id, SomeObj*> p = GetNext();
vec[p.first] = p.second;

问题是std::vector使用自己的类型来索引其元素:std::vector::size_type(为什么不是模板化的?)。

严格来说,使用std::map<Id, SomObj*>会更好,但效率会降低,而且数组就是我真正需要的(我知道所有对象的索引都是连续的并以{开头} {1}})。另一个问题是0将来可能会更改为typedef int Id或类似...(虽然它是我自己代码的一部分,所以我控制它,但理想情况下我应该允许更改typedef long int Id在某些方面;这就是typedef的用途。)

你会怎么处理这个?也许使用typedef,其中哈希函数直接使用unordered_map<Id, SomeObj*>作为哈希键?这会降低内存效率吗? (我不完全理解Id如何预先知道散列函数的范围是否会分配其空间?)

4 个答案:

答案 0 :(得分:4)

您可以将任何整数类型作为std::vector的索引传递。如果它与std::vector<T>::size_type(通常为unsigned long)不匹配,则会隐式转换该值。

答案 1 :(得分:3)

  

为什么不是那个模板?

因为标准容器被实现为使用它们合理可以使用的最大无符号类型。如果您的实施中size_typeunsigned int,那么这是有原因的,无论原因是什么阻止了使用更大类型的实施者,如果您要求其他东西[*],它仍然存在。此外,对于您的特定示例,大小类型必须是无符号的,并且您希望使用签名类型,因此这是支持您想要执行的操作所需的另一个更改。

在实践中,标准容器的size_type(几乎?)总是size_t。因此,如果您要求更大的向量,则不能有一个向量,因为向量由连续存储支持。向量将无法分配大于size_t字节的数组。

要使用Id作为向量索引,您可以依赖隐式转换,也可以显式转换(也可以显式绑定检查),以便清楚地了解您正在做什么。您还可以使用断言来确保Id不大于size_type。像这样的东西,虽然静态断言可能会更好:

assert(std::numeric_limits<Id>::max() <= std::numeric_limits<std::vector<SomeObj*>::size_type>::max());

如果使用的Id值稀疏,则map<Id, SomeObj*>将是一个不错的选择。如果唯一有效的Ids是1和400,000,000,则向量将相当浪费内存。

如果它让您感觉更舒服,请记住文字0的类型为int,而不是vector<SomeObj*>::size_type。大多数人对编写vec[0]没有任何疑虑:确实在标准中使用了它。

[*]即使这个原因只是,“实施者认为40亿元素足以让任何人”。

答案 2 :(得分:2)

编写自己的容器包装器,将Id作为索引类型。在内部使用mapunordered_map来实现容器。针对此包装器的程序。如果事实证明此实施太慢,请在内部切换到vector并将Id索引转换为vector::size_type(当然也在内部)。

这是最干净的方法。但实际上,vector::size_type将是一些非常大的无符号整数类型,因此从Idvector::size_type的转换始终是安全的(但不是相反!)。

答案 3 :(得分:0)

问题是,Idint(更确切地说,signed int),可能是否定的。如果Id是无符号类型,例如typedef unsigned int Id;,没有问题。

如果到目前为止我的理解是正确的,那么我不明白为什么有人想要使用负数作为vector(或array)的索引。我错过了什么?