我什么时候应该使用std :: size_t?

nha*_*123 187 c++ types idiomatic size-t loop-counter

我只是想知道我应该使用std::size_tfor循环和东西而不是int?例如:

#include <cstdint>

int main()
{
    for (std::size_t i = 0; i < 10; ++i) {
        // std::size_t OK here? Or should I use, say, unsigned int instead?
    }
}
Run Code Online (Sandbox Code Playgroud)

一般来说,何时使用的最佳做法是什么std::size_t

CB *_*ley 172

一个好的经验法则是你需要在循环条件下比较自然的东西std::size_t.

std::size_t是任何sizeof表达式的类型,并且保证能够在C++中表达任何对象(包括任何数组)的最大大小.通过扩展,它也保证足够大,可以用于任何数组索引,因此它是一个循环索引的自然类型.

如果你只计算一个数字,那么使用保存该数字的变量的类型或者int或者unsigned int(如果足够大)可能更自然,因为这些应该是机器的自然大小.

  • 值得一*不*使用`size_t`提的是,当你应该可以导致[安全漏洞](http://stackoverflow.com/questions/3259413/should-you-always-use-int-for-numbers-in- C-偶数如果-它们-是-非负/ 3261019#3261019). (39认同)
  • int不仅是"自然的",而且混合有符号和无符号类型也会导致安全漏洞.无符号索引是一个难以处理的问题,也是使用自定义矢量类的一个很好的理由. (2认同)
  • @JoSo 还有用于有符号值的“ssize_t”。 (2认同)

Gre*_*osz 70

size_tsizeof运算符的结果类型.

使用size_t变量数组中的模型的大小或指数.size_t传达语义:你立即知道它代表一个字节大小或索引,而不只是另一个整数.

此外,size_t用于表示字节大小有助于使代码可移植.


pax*_*blo 31

size_t类型用于指定某些内容的大小,因此使用它是很自然的,例如,获取字符串的长度然后处理每个字符:

for (size_t i = 0, max = strlen (str); i < max; i++)
    doSomethingWith (str[i]);
Run Code Online (Sandbox Code Playgroud)

必须注意,当然边界条件,因为它是一个无符号类型.因为最大通常比较大(虽然它在高端产品的界限通常不是重要的可以到那里).大多数人只是使用一种int东西,因为他们很少有足够大的结构或阵列来超过容量int.

但请注意以下事项:

for (size_t i = strlen (str) - 1; i >= 0; i--)
Run Code Online (Sandbox Code Playgroud)

由于无符号值的包装行为,这将导致无限循环(虽然我看到编译器警告这一点).这也可以通过(稍微难以理解,但至少不受包装问题影响)来缓解:

for (size_t i = strlen (str); i-- > 0; )
Run Code Online (Sandbox Code Playgroud)

通过将递减转换为连续条件的后检查副作用,这将递减之前检查值的继续,但仍然使用循环内的递减值(这是循环运行len .. 1而不是len-1 .. 0)的原因.

  • 顺便说一下,在循环的每次迭代中调用`strlen`是一种不好的做法.:)你可以这样做:`for(size_t i = 0,len = strlen(str); i <len; i ++)...` (14认同)
  • 正确倒计时可以通过以下(臭名昭着)方式完成:`for(size_t i = strlen(str); i - > 0;)` (2认同)

Dan*_*nas 12

根据定义,size_tsizeof运营商的结果.size_t是为了引用尺寸而创建的.

您执行某些操作的次数(在您的示例中为10)与尺寸无关,为什么要使用size_tint,或者unsigned int,应该没问题.

当然,你i在循环中做的也很重要.如果你将它传递给一个带有unsigned int例如pick 的函数unsigned int.

无论如何,我建议避免隐式类型转换.明确所有类型转换.


小智 10

size_t是一种非常易读的方式来指定项目的大小维度 - 字符串的长度,指针占用的字节数等等.它也可以跨平台移植 - 你会发现64位和32位都能很好地处理系统功能和size_t-东西,unsigned int什么时候应该使用也许不会那么做(如unsigned long


Pet*_*der 8

使用std :: size_t索引/计数C样式数组.

对于STL容器,您将拥有(例如)vector<int>::size_type,它应该用于索引和计算向量元素.

实际上,它们通常都是无符号整数,但不能保证,特别是在使用自定义分配器时.

  • 对于`vector <T> :: size_type`(以及所有其他容器的ditto),它实际上相当无用,因为它实际上保证为`size_t` - 它的类型定义为'Allocator :: size_type`,并且关于容器的限制见20.1.5/4 - 特别是`size_type`必须是`size_t`,`difference_type`必须是`ptrdiff_t`.当然,默认的`std :: allocator <T>`满足这些要求.所以只需使用较短的`size_t`,不要打扰其余部分:) (8认同)
  • 但是,由于索引可能是负数,所以C风格的数组不会被`size_t`索引.但是,如果一个人不想消极,那么可以使用`size_t`作为这样一个数组的实例. (5认同)
  • 使用linux上的gcc,`std :: size_t`通常是`unsigned long`(64位系统上的8个字节),而不是`unisgned int`(4个字节). (2认同)
  • 由于C风格的数组索引相当于在指针上使用运算符`+`,所以看起来`ptrdiff_t`是用于索引的那个. (2认同)

Nor*_*löw 8

很快,大多数计算机将采用64位操作系统的64位架构:运行在数十亿元素容器上运行的程序.然后,你必须使用size_t,而不是int作为循环索引,否则你的索引将环绕在2 ^ 32:th元素,在32位和64位系统.

为未来做好准备!


Arn*_*rne 7

简答:

几乎从不

答案很长:

每当你需要在32位系统上使用大于2gb的char向量时.在每个其他用例中,使用带符号类型比使用无符号类型更安全.

例:

std::vector<A> data;
[...]
// calculate the index that should be used;
size_t i = calc_index(param1, param2);
// doing calculations close to the underflow of an integer is already dangerous

// do some bounds checking
if( i - 1 < 0 ) {
    // always false, because 0-1 on unsigned creates an underflow
    return LEFT_BORDER;
} else if( i >= data.size() - 1 ) {
    // if i already had an underflow, this becomes true
    return RIGHT_BORDER;
}

// now you have a bug that is very hard to track, because you never 
// get an exception or anything anymore, to detect that you actually 
// return the false border case.

return calc_something(data[i-1], data[i], data[i+1]);
Run Code Online (Sandbox Code Playgroud)

签名的等价物size_tptrdiff_t,不是int.但int在大多数情况下,使用仍然比size_t好得多.ptrdiff_tlong在32个64位系统.

这意味着每当你与std :: containers进行交互时,你总是必须与size_t进行转换,这不是很漂亮.但是在一个正在进行的原生会议上,c ++的作者提到用无符号size_t设计std :: vector是一个错误.

如果编译器为您提供了从ptrdiff_t到size_t的隐式转换的警告,则可以使用构造函数语法使其显式:

calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);
Run Code Online (Sandbox Code Playgroud)

如果只是想迭代一个集合,没有边界检查,使用范围基于:

for(const auto& d : data) {
    [...]
}
Run Code Online (Sandbox Code Playgroud)

这里有来自Bjarne Stroustrup(C++作者)的一些关于本土的话

对于某些人来说,STL中这个签名/未签名的设计错误是合理的,不使用std :: vector,而是使用自己的实现.

  • 我知道它们来自哪里,但我仍然认为编写 `for(int i = 0; i &lt; get_size_of_stuff(); i++)` 很奇怪。现在,当然,您可能不想做很多原始循环,但是 - 来吧,您也使用它们。 (2认同)

小智 6

size_t 由各种库返回,以指示该容器的大小不为零。你回来一次就用它:0

但是,在上面的示例中,循环 size_t 是一个潜在的错误。考虑以下:

for (size_t i = thing.size(); i >= 0; --i) {
  // this will never terminate because size_t is a typedef for
  // unsigned int which can not be negative by definition
  // therefore i will always be >= 0
  printf("the never ending story. la la la la");
}
Run Code Online (Sandbox Code Playgroud)

使用无符号整数有可能产生这些类型的微妙问题。因此,恕我直言,我更喜欢仅在与需要它的容器/类型交互时才使用 size_t 。