【问题标题】:Correct usage of vector<int>::size_type正确使用 vector<int>::size_type
【发布时间】:2018-08-13 08:22:31
【问题描述】:

我在一些非常著名的 C++ 书籍中看到了 --

vector<int> ivec;

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec.push_back(i);
    ivec.push_back(i);  // duplicate copies of each number

}

我想知道为什么在这里使用vector&lt;int&gt;::size_type。他们不是 将i 与向量的大小进行比较。意图是插入10个int's 矢量,所以int i = 0 是正确的做法,不是吗?

vector&lt;int&gt;::size_type 将是 typedef 对于 std::size_t 反过来将 是unsinged int,但这里我们将int 存储在vector 中。

请澄清我对vector&lt;int&gt;::size_type的理解。在上面的for循环中使用它公平吗?

【问题讨论】:

  • 一般情况下使用ptrdiff_t,例如命名为Size。这是一个签名类型,因此您可以避免在代码中引入错误的简单促销。此外,您还避免了在尝试使用 size_type 定义时过度吸引错误的代码复杂性(恕我直言,现代 C++ 编码中盲目一致性的最愚蠢的方面;这都是负值,被认为是相反的)。跨度>
  • 我同意int 是这里更自然的选择。但是,重要的是您的循环不会导致溢出。如果你写了一个类似的循环,但使用i != x而不是i != 10,并且x可能大于INT_MAX,那么你必须小心。
  • 在我看来这太迂腐了,只需使用 int 作为日常向量,您不需要 2GB 向量,并且在极少数情况下您发现自己需要它,您非常清楚需要付费无论如何都要特别注意。
  • @Pavan Manjunath 我已经经历过这个,我的问题是 - 在代码中使用它是否公平?我认为这不公平,但我想澄清(赞同)我的理解。

标签: c++ c++11


【解决方案1】:

基本上,正如其他人所说,上面的代码在编译和完成预期工作的意义上是“好的”。

当他们说打算在向量中插入十个 ints 时,由于循环的格式,ints 保证为正值,因此 unsigned int 只会转换为 int

但是,我认为这不是您所说的好习惯-尺寸类型与插入元素的类型无关-尺寸类型基本上总是unsigned int。仅仅使用intvalue_type 显然会使代码的意图更加清晰。

【讨论】:

  • 哪些书仍然使用该循环?
  • 有趣。我有那本书,似乎作者可能出于习惯的“传统”这样做,因为尺寸类型将始终包含矢量可以拥有的 最大 索引。好的代码永远不会溢出,但我想这是一种预防措施,以防实际发生溢出。老实说,这样做并没有错 - 只是在您编写“好”代码时大部分时间都不需要。
  • 在这种情况下,它们甚至没有遍历向量的每个元素,只是添加了 10 个值。可能只是习惯。
  • 请注意:size_tunsigned int 不同:size_t 取决于内存地址大小sizeof(void*),而 unsigned int 可能小至 16 位。例如。在 8 位 MCU 上,unsigned int 可能是 16 位,而 size_t 可能是 8 位。
  • 另一个 Stack Overflow 回答者认为不是:stackoverflow.com/questions/18810800/… 我认为对于大多数实现,size_t 是一个无符号整数,但它毕竟是实现定义的。
【解决方案2】:

我会说不,这段代码不正确,许多编译器会警告从 size_tint 的隐式转换。

vector::size_type/size_t 应始终用于矢量索引,但如果您有一个 vectorint,那么您应该将 ints 插入其中。

正确的代码是:

vector<int> ivec;

for (vector<int>::value_type i = 0; i != 10; ++i) {
    ivec.push_back(i);
    ivec.push_back(i);  // duplicate copies of each number
}

for (vector<int>::size_type i = 0; i < ivec.size(); ++i) {
    std::cout << ivec[i] << "\n";
}

【讨论】:

  • 为什么说“不正确”?它做它应该做的。在这种情况下,将size_t 隐式转换为int 是明确定义的。如果编译器对此发出警告,那是因为它没有对代码进行足够彻底的分析。我并不是说这段代码 100% 漂亮,但称其为“不正确”并不正确。
  • 好的,在这种情况下,数字是 0-10,所以没有问题,但根据我的经验,编译器不一定会深入分析代码,并且会警告此代码。在一般情况下,数字可能不在这两种类型的有效范围内,然后会出现细微的错误
  • 如果在 for 循环中使用了比 INT_MAX 更大的数字,那么此代码将有一个真正的问题(您和 OP 的版本也是如此)。但如果范围更小,那么两个版本都可以。
  • @geza 除了负数并假设size_t 大于或与int 相同大小,但不一定是这种情况
  • 如果size_t 小于int,那么两个版本仍然有问题,因为你不能在向量中添加比SIZE_MAX 更多的元素(这里我们不考虑负数,因为原始示例没有它们)。
【解决方案3】:

为避免隐式转换和编译器警告,您可以明确说明 push_back

vector<int> ivec;

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec.push_back(static_cast<int>(i));
    ivec.push_back(static_cast<int>(i));
}

在这段代码中使用size_typestatic_cast 似乎是人为的。在下面的例子中会更有意义(@AlanBirtles 的例子的组合):

vector<int> ivec(20);

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec[2 * i] = ivec[2 * i + 1] = static_cast<int>(i);
}

【讨论】:

    【解决方案4】:

    一般

    是的,你的类型是int

    但这不是size_type 所说的。 size_type 是向量的索引 的类型。它是向量 size 的类型(因此得名!)。

    我们为此使用类型别名(由标准库提供),因为它可能/将会因系统而异。它通常是size_t,它本身就是一些大型无符号类型的标准别名,尽管对于可移植程序来说,您通常无法预测它。


    但是……!

    这个特定的例子令人倍感困惑,因为本书作者确实是在使用尺寸类型填充向量。这不一定是“错误的”:在 0-9 范围内,它不会中断。编译器只会以通常的方式隐式转换整数。

    但它表达的意图不正确。

    我想它曾经是这样的:

    vector<int> v(5);
    for (vector<int>::size_type i = 0; i < v.size(); i++)
       v[i] = 42;
    

    然后有人更改了循环体(这样i 现在用于值,而不是用于索引)并且没有考虑更改循环前导码。

    i 变成int 会更加清晰和明显。

    总体而言,我会考虑避免使用这些“知名书籍”,或者至少检查它们的勘误表以查看代码是否在发布后进行了调整,因为这是一个非常奇怪的 C++ 示例。

    【讨论】:

      猜你喜欢
      • 2020-03-06
      • 2021-01-26
      • 1970-01-01
      • 2016-03-05
      • 2023-03-03
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多