【问题标题】:How to use an unknown (int-like) type as index into std::vector?如何使用未知(类 int)类型作为 std::vector 的索引?
【发布时间】:2010-09-22 15:23:57
【问题描述】:

我正在使用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&lt;Id, SomObj*&gt;会更好,但是这样效率会更低,而且我这里真正需要的是一个数组(我知道所有对象的索引都是连续的,并且以0开头)。另一个问题是typedef int Id 将来可能会更改为typedef long int Id 或类似的......(虽然它是我自己代码的一部分,所以我控制它,但理想情况下我应该被允许更改typedef at一些要点;这就是 typedef 的用途)。

你会如何处理这个问题?也许使用unordered_map&lt;Id, SomeObj*&gt;,其中哈希函数直接使用Id作为哈希键?那会不会降低内存效率? (我不完全明白unordered_map是如何分配空间的,因为事先不知道hash函数的范围?)

【问题讨论】:

  • 你错过了最后一段中的反引号。

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


【解决方案1】:

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

【讨论】:

  • 我 90% 确定 vector&lt;T&gt;::size_type 不是unsigned long。相反,它几乎总是std::size_t,在某些计算机上是long 的两倍。
  • 是的,size_type 可能是size_t。但是,这通常是unsigned long。它在我的带有 gcc 的 64 位 linux 系统和我的 32 位 Windows 系统上。
  • 64 位 Windows 是非典型的,因为它是 LLP64,而 64 位 linux 是 LP64。
  • @Steve:好点;在 64 位 Windows 上,size_t 可能是 unsigned __int64
【解决方案2】:

为什么没有模板化?

因为标准容器被实现为尽可能使用最大的无符号类型。如果在您的实现中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&lt;Id, SomeObj*&gt; 将是一个不错的选择。如果唯一有效的 Id 是 1 和 400,000,000,那么向量将相当浪费内存。

如果它让您感觉更舒服,请记住文字 0 的类型为 int,而不是 vector&lt;SomeObj*&gt;::size_type。大多数人都毫不犹豫地写vec[0]:确实在标准中使用。

[*] 即使这个理由是公正的,“实施者认为 40 亿个元素对任何人来说都足够了”。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      问题是,Id 是一个int(更准确地说是signed int),可以是负数。如果 Id 是无符号类型,例如typedef unsigned int Id;,没问题。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-27
        • 2021-05-14
        • 1970-01-01
        • 1970-01-01
        • 2020-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多