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

时间:2009-12-23 09:02:01

标签: c++ types idiomatic size-t loop-counter

我只是想知道我应该使用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

的最佳做法是什么?

13 个答案:

答案 0 :(得分:163)

一个好的经验法则是你需要在循环条件下与任何自然为std::size_t的东西进行比较。

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

如果您只计算一个数字,那么使用包含该数字的变量类型或intunsigned int(如果足够大)可能更为自然应该是机器的自然尺寸。

答案 1 :(得分:68)

size_tsizeof运算符的结果类型。

对模型中的大小或索引建模的变量使用size_tsize_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_tsizeof运算符的结果。创建size_t是为了引用尺寸。

您执行某些操作的次数(在您的示例中为10)与尺寸无关,那么为什么要使用size_tintunsigned 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_tptrdiff_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)]);

来自going native

的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.