什么时候应该使用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
是任何sizeof
expression式的types,并且保证能够在C ++中表示任何对象(包括任何数组)的最大大小。 通过扩展,它也保证足够大的任何数组索引,所以它是一个循环的数组索引的自然types。
如果只计算一个数字,那么使用保存该数字的variables的types或者int
或unsigned int
(如果足够大的话)可能更自然一些,因为它们应该是机器的自然尺寸。
size_t
是sizeof
运算符的结果types。
将size_t
用于模型中数组大小或索引的variables。 size_t
expression了语义:你马上知道它代表了一个以字节为单位的大小或一个索引,而不仅仅是另一个整数。
此外,使用size_t
来表示以字节为单位的大小有助于使代码具有可移植性。
size_t
types是为了指定一些东西的大小 ,所以很自然的使用它,例如获取一个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_t
是sizeof
运算符的结果。 size_t
是为了引用大小而创build的。
你做某事的次数(在你的例子中是10)不是大小,所以为什么要用size_t
? int
或unsigned int
,应该没问题。
当然,这也是相关的你在循环里面做什么。 如果你把它传递给一个带有unsigned int
的函数,例如,selectunsigned int
。
无论如何,我build议避免隐式types转换。 使所有types转换明确。
size_t
是一个非常可读的方式来指定项目的大小维度 – string的长度,指针所需的字节数量等。它也可以跨平台移植 – 你会发现64位和32位都很好地处理系统函数和size_t
– unsigned 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++) { }