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

我只是想知道应该使用std::size_t循环和东西而不是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? } } 

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

一个好的经验法则是,你需要在循环条件中比较任何自然是std::size_t本身的东西。

std::size_t是任何sizeofexpression式的types,并且保证能够在C ++中表示任何对象(包括任何数组)的最大大小。 通过扩展,它也保证足够大的任何数组索引,所以它是一个循环的数组索引的自然types。

如果只计算一个数字,那么使用保存该数字的variables的types或者intunsigned int (如果足够大的话)可能更自然一些,因为它们应该是机器的自然尺寸。

size_tsizeof运算符的结果types。

size_t用于模型中数组大小或索引的variables。 size_texpression了语义:你马上知道它代表了一个以字节为单位的大小或一个索引,而不仅仅是另一个整数。

此外,使用size_t来表示以字节为单位的大小有助于使代码具有可移植性。

size_ttypes是为了指定一些东西的大小 ,所以很自然的使用它,例如获取一个string的长度然后处理每个字符:

 for (size_t i = 0, max = strlen (str); i < max; i++) doSomethingWith (str[i]); 

当然,你必须小心边界条件,因为它是一个无符号types。 高端的边界通常不是那么重要,因为最高边界通常很大(尽pipe可能到达那里)。 大多数人只是使用int来处理这种事情,因为他们很less有足够大的结构或者数组来超过int的容量。

但要小心这样的事情:

 for (size_t i = strlen (str) - 1; i >= 0; i--) 

这会由于无符号值的包装行为而导致无限循环(尽pipe我见过编译器对此提出警告)。 这也可以通过(稍微难以理解,但至less免疫包装问题)来缓解:

 for (size_t i = strlen (str); i-- > 0; ) 

通过将递减移位到继续条件的检查后副作用,可以递减之前对值进行检查,但仍然使用循环内的递减值(这就是为什么循环从len .. 1而不是len-1 .. 0 )。

根据定义, size_tsizeof运算符的结果。 size_t是为了引用大小而创build的。

你做某事的次数(在你的例子中是10)不是大小,所以为什么要用size_tintunsigned int ,应该没问题。

当然,这也是相关的你在循环里面做什么。 如果你把它传递给一个带有unsigned int的函数,例如,selectunsigned int

无论如何,我build议避免隐式types转换。 使所有types转换明确。

size_t是一个非常可读的方式来指定项目的大小维度 – string的长度,指针所需的字节数量等。它也可以跨平台移植 – 你会发现64位和32位都很好地处理系统函数和size_tunsigned int可能不会做的事情(例如,当你应该使用unsigned long

使用std :: size_t来索引/计数C风格的数组。

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

实际上,它们通常都是未签名的整数,但不能保证,特别是在使用自定义分配器时。

不久,大多数计算机将成为64位操作系统的64位架构:运行程序运行在数十亿个元素的容器上。 那么你必须使用size_t而不是int作为循环索引,否则你的索引将在32位和64位系统上的2 ^ 32:th元素中进行回绕

为未来做准备!

简短的回答:

几乎从不

长答案:

每当你需要在32位系统上有一个大于2GB的char向量时, 在其他任何用例中,使用带符号的types比使用无符号的types安全得多。

例:

 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]); 

size_t的符号等价物是ptrdiff_t ,而不是int 。 但是在大多数情况下使用int仍然比size_t好得多。 ptrdiff_t在32位和64位系统上很long

这意味着每当你与一个std :: containers进行交互的时候,你总是必须转换成size_t,而不是那么漂亮。 但在本土会议上,c ++的作者提到用unsigned size_tdevisestd :: vector是一个错误。

如果编译器给出了有关从ptrdiff_t到size_t的隐式转换的警告,则可以使用构造函数语法使其显式化:

 calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]); 

如果只是想迭代一个集合,而没有限制,则使用基于范围的:

 for(const auto& d : data) { [...] } 

这里有一些来自Bjarne Stroustrup(C ++作者)的原文

对于一些人来说,STL中这个有符号/无符号的devise错误是足够的理由,不要使用std :: vector,而是使用自己的实现。

使用size_t时,请注意以下expression式

 size_t i = containner.find("mytoken"); size_t x = 99; if (ix>-1 && i+x < containner.size()) { cout << containner[ix] << " " << containner[i+x] << endl; } 

不pipex的值是多less,你都会在ifexpression式中得到错误的结果。 我花了几天的时间才意识到这一点(代码非常简单,我没有做unit testing),但只花了几分钟的时间才能找出问题的根源。 不知道最好是做一个演员或使用零。

 if ((int)(ix) > -1 or (ix) >= 0) 

这两种方式应该工作。 这是我的testing运行

 size_t i = 5; cerr << "i-7=" << i-7 << " (int)(i-7)=" << (int)(i-7) << endl; 

输出:i-7 = 18446744073709551614(int)(i-7)= – 2

我想其他人的意见。

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"); } 

使用无符号整数有可能产生这些types的微妙问题。 因此,我只喜欢使用size_t当我与需要它的容器/types进行交互时。

size_t是一个无符号types,可以为你的体系结构保存最大的整数值,所以它可以防止由于符号的整数溢出(signed int 0x7FFFFFFF增加1会给你-1)或者缩小尺寸(unsigned short int 0xFFFF增加1给你0)。

它主要用于数组索引/循环/地址运算等。 像memset()类的函数只接受size_t ,因为理论上你可能有一个2^32-1大小的内存块(在32位平台上)。

对于这样简单的循环,不要打扰,只使用int。

size_t是无符号整数。 它用来隐藏平台的详细信息。

size_t是一个无符号整数types,它可以表示你系统上最大的整数。 只有当你需要非常大的数组,matrix等时才使用它。

有些函数会返回size_t,如果您尝试进行比较,编译器会发出警告。

避免通过使用适当的有符号/无符号数据types或简单的types转换来实现快速入侵。

size_t是无符号整数。 所以只要你想unsigned int,你可以使用它。

我使用它时,我想指定数组的大小,计数器等…

 void * operator new (size_t size); is a good use of it. 
 for (i=0; i<Array.GetCount()-1, i++) { } 

GetCount()返回一个size_t

如果数组为空,这个正确的代码就会出错。

size_t最大化可以返回的计数,但这是一个严重的危险。 我感叹它的广泛使用。 这意味着很多代码变得危险或者丑陋:

 for (i=0; i<(int)(Array.GetCount())-1, i++) { }