【问题标题】:difference between size_type and intsize_type 和 int 的区别
【发布时间】:2014-03-16 13:01:18
【问题描述】:
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<double> student_marks(20);

    for (vector<double>::size_type i = 0; i < 20; i++)
    {
        cout << "Enter marks for student #" << i+1 
            << ": " << flush;
        cin >> student_marks[i];
    }
    return 0;
}

我在某处读到最好使用 size_type 代替 int 。它真的会对实施产生巨大影响吗?使用 size_type 有什么好处?

【问题讨论】:

  • size_type 将能够保存所有索引,并且在您执行 i &lt; student_marks.size() 时不会发出警告。
  • 在 for 循环中使用i &lt; student_marks.size() 作为条件更为重要,或者使用迭代器更好:for (auto it = student_marks.begin(); it &lt; student_marks.end(); ++it)。然后,您可以使用*it 访问向量元素,例如cin &gt;&gt; *it.
  • @ChristianAichinger 是的,我正在阅读有关向量的内容,遇到了这个玩具示例,这就是我发布的原因。

标签: c++ vector stl


【解决方案1】:

vector&lt;double&gt;::size_type 保证覆盖vector&lt;double&gt; 大小的所有可能值。 int 不是。

请注意vector&lt;double&gt;::size_type 通常与std::size_t 相同,因此通常使用后者就可以了。但是,自定义分配器可能会导致 size_typestd::size_t 不同的向量。

【讨论】:

    【解决方案2】:

    size_type 是一个无符号数字。这意味着它不能为负数。对于容器大小,这听起来可能是合乎逻辑的选择,但在现实生活中会产生很多问题

    例如,当您从另一个中减去一个 size_type 时,如果第二个操作数大于第一个操作数,则结果将默默地转换为一个巨大的正数:

    std::vector<double>::size_type size1 = v1.size();
    std::vector<double>::size_type size2 = v2.size();
    if ((size1 - size2) > 5) // dangerous if v2 is bigger than v1!
    {
        // ...
    }
    

    而且它经常使错误检查变得不可能:

    void f(std::vector<double>::size_type size)
    {
        if (size < 0)
        {
            // error handling will never be reached    
        }
    }
    
    f(-1); // no error handling
    

    对于此类问题,您通常在代码中更喜欢(有符号)int 而不是unsigned,不幸的是,标准库容器将它们的大小表示为无符号数字。您通常希望尽快将 (static_cast) 大小转换为有符号数字。在您的示例中,保持无符号很好,因为它只是循环索引,并且首先转换为 int 会过度设计 IMO。

    好消息是,您通常可以通过使用迭代器完全避免size_type

    for (std::vector<double>::const_iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        std::cout << *iter;
    }
    

    我邀请您看看 Scott Meyers 的 Signed and Unsigned Types in Interfaces

    最后,请注意,经验丰富的 C++ 程序员并未普遍认同这种观点。在网络上搜索有关此主题的过去讨论(旧的 Stackoverflow 问题、comp.lang.c++ Usenet 存档等)会发现不同的意见。

    【讨论】:

      【解决方案3】:

      使用size_type 而不是size_t 的好处只是顺从。它取悦那些死记硬背、纯粹通过联想进行推理的人。他们确实喜欢看到别人和自己一样,并希望这被认为是“正确的”。

      size_type 成员是容器大小类型的自定义点。它来自分配器模板参数。对于默认的标准分配器,它只是size_t 的同义词,即默认情况下,它们是相同的类型

      int 的问题与 ptrdiff_t(指针差异的结果类型)相反,问题在于 int 在 64 位系统上可能没有足够的范围来处理非常大的向量.

      size_t 的问题在于它很容易导致在混合类型表达式中无意使用模运算。例如,表达式std::string( "Hi!" ).length() &lt; -7 将始终产生true。因此,它是一个 bug 吸引器,所以ptrdiff_t,或者当你确定范围时只是简单的int,在客观上是非常可取的(尽管它可能会让上述人非常不高兴——仍然有一个非常强大的社交使用客观较差的解决方案的压力)。

      在标准库中,无符号类型 size_t 用于历史原因

      特别是,在 16 位系统上,内存是一种非常有限的资源,必须使用每一个小技巧才能完全利用它——对于那些小系统,在那些日子里,这是非常值得的一些环绕错误等的风险。今天不是。

      【讨论】:

      • 如果您执行 size_type &lt; signed int 会发生什么 - 您是说有符号的 int 不会转换为无符号的,但如果您执行了 size_t &lt; signed int,它会?
      • @GavinSmith:你不能像你的例子那样比较类型,但你可以比较实例/值。但是,根据您的意图,没有size_typesize_t 相比没有任何优势。使用标准库容器的默认模板参数 size_type is size_t。我更新了答案以提及这一点。谢谢。
      • +1 感谢您提供了足够详细的信息,让我真正理解其中的推理,并且可以自信地做出自己的设计决策。
      • @PorkyBrain:不客气。在各种数据处理中,请注意向后兼容性(这就是size_t 的意义所在)!例如,昨天我得知 Microsoft Excel 接受 1900 年 2 月 29 日的日期,从而在其天数计数中引入了 1 个错误,只是为了与曾经是其主要竞争对手的现在过时的 VisiCalc 中的一个错误兼容.到处都是这样。在某种程度上。 ;-)
      猜你喜欢
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-06
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      相关资源
      最近更新 更多