我只是想知道我应该使用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
?
答案 0 :(得分:163)
一个好的经验法则是你需要在循环条件下与任何自然为std::size_t
的东西进行比较。
std::size_t
是任何sizeof
表达式的类型,并且保证能够表达C ++中任何对象(包括任何数组)的最大大小。通过扩展,它也可以保证足够大,适用于任何数组索引,因此它是一个循环索引的自然类型。
如果您只计算一个数字,那么使用包含该数字的变量类型或int
或unsigned int
(如果足够大)可能更为自然应该是机器的自然尺寸。
答案 1 :(得分:68)
size_t
是sizeof
运算符的结果类型。
对模型中的大小或索引建模的变量使用size_t
。 size_t
传达语义:你立即知道它代表一个字节大小或索引,而不仅仅是另一个整数。
此外,使用size_t
表示以字节为单位的大小有助于使代码可移植。
答案 2 :(得分:30)
size_t
类型用于指定某些内容的 size ,因此使用它是很自然的,例如,获取字符串的长度然后处理每个字符:
for (size_t i = 0, max = strlen (str); i < max; i++)
doSomethingWith (str[i]);
你做当然必须注意边界条件,因为它是无符号类型。顶端的边界通常不那么重要,因为最大值通常很大(尽管 可能到达那里)。大多数人只是使用int
来做这类事情,因为他们很少有足够大的结构或数组超过int
的容量。
但请注意以下事项:
for (size_t i = strlen (str) - 1; i >= 0; i--)
由于无符号值的包装行为会导致无限循环(虽然我看过编译器警告过这种情况)。这也可以通过(稍微难以理解但至少不受包装问题影响)来缓解:
for (size_t i = strlen (str); i-- > 0; )
通过将递减转换为连续条件的后检查副作用,这将检查减去之前的值的继续,但仍然使用循环内的递减值(这就是循环从len .. 1
开始而不是len-1 .. 0
)的原因。
答案 3 :(得分:12)
根据定义,size_t
是sizeof
运算符的结果。创建size_t
是为了引用尺寸。
您执行某些操作的次数(在您的示例中为10)与尺寸无关,那么为什么要使用size_t
? int
或unsigned int
应该没问题。
当然,你在循环中对i
所做的事情也很重要。例如,如果将其传递给采用unsigned int
的函数,请选择unsigned int
。
无论如何,我建议避免隐式类型转换。 Make all type conversions explicit.
答案 4 :(得分:10)
size_t
是一种非常易读的方法,用于指定项的大小维度 - 字符串的长度,指针所占的字节数等。
它也可以跨平台移植 - 你会发现64位和32位都能很好地处理系统功能和size_t
- unsigned int
可能不会做的事情(例如你应该何时使用unsigned long
答案 5 :(得分:8)
使用std :: size_t索引/计数C风格的数组。
对于STL容器,您将拥有(例如)vector<int>::size_type
,它应该用于索引和计算向量元素。
实际上,它们通常都是无符号整数,但不能保证,尤其是在使用自定义分配器时。
答案 6 :(得分:6)
很快,大多数计算机将成为64位操作系统的64位架构:运行在数十亿元素容器上运行的程序。然后你必须使用size_t
代替int
作为循环索引,否则你的索引将环绕在2 ^ 32:th元素,on 32位和64位系统。
为未来做好准备!
答案 7 :(得分:6)
几乎从未
每当你需要在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]);
签名的等效size_t
为ptrdiff_t
,而不是int
。但是在大多数情况下使用int
仍然比size_t好得多。 <{1}}在32位和64位系统上为ptrdiff_t
。
这意味着每当你与std :: containers进行交互时,你总是必须与size_t进行转换,这不是很漂亮。但在一个正在进行的原生会议上,c ++的作者提到用无符号size_t设计std :: vector是一个错误。
如果编译器为您提供了从ptrdiff_t到size_t的隐式转换的警告,您可以使用构造函数语法使其显式:
long
如果只想迭代一个集合,没有边界检查,请使用基于:
的范围calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);
的Bjarne Stroustrup(C ++作者)的一些话
对于某些人来说,STL中这个签名/未签名的设计错误是合理的,不使用std :: vector,而是使用自己的实现。
答案 8 :(得分:3)
使用size_t时,请注意以下表达式
size_t i = containner.find("mytoken");
size_t x = 99;
if (i-x>-1 && i+x < containner.size()) {
cout << containner[i-x] << " " << containner[i+x] << endl;
}
无论x对x有什么价值,if表达式都会出错。 我花了好几天才意识到这一点(代码非常简单,我没有进行单元测试),尽管只需要几分钟就可以找出问题的根源。不确定进行强制转换或使用零是否更好。
if ((int)(i-x) > -1 or (i-x) >= 0)
两种方式都应该有效。这是我的试运行
size_t i = 5;
cerr << "i-7=" << i-7 << " (int)(i-7)=" << (int)(i-7) << endl;
输出:i-7 = 18446744073709551614(int)(i-7)= - 2
我想要其他人的评论。
答案 9 :(得分: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");
}
使用无符号整数有可能产生这些类型的微妙问题。因此,只有当我与需要它的容器/类型进行交互时,我才更喜欢使用size_t。
答案 10 :(得分:-1)
size_t
是一个无符号类型,可以为您的体系结构保存最大整数值,因此它可以防止由于符号引起的整数溢出(signed int 0x7FFFFFFF
递增1会给你-1)或者短大小(无符号短整数0xFFFF加1会给你0)。
主要用于数组索引/循环/地址算法等。像memset()
这样的函数只接受size_t
,因为理论上你可能有一块大小为2^32-1
的内存块(在32位平台上)。
对于这样的简单循环,不要打扰并仅使用int。
答案 11 :(得分:-3)
size_t是无符号整数类型,可以表示系统上的最大整数。 只有在需要非常大的数组,矩阵等时才使用它。
某些函数返回size_t,如果您尝试进行比较,编译器会发出警告。
通过使用适当的有符号/无符号数据类型或简单地进行类型转换来避免快速入侵。
答案 12 :(得分:-4)
size_t是unsigned int。所以无论何时你想要unsigned int,你都可以使用它。
当我想指定数组的大小时,我会使用它,反...等等。
void * operator new (size_t size); is a good use of it.