我只是想知道我是否应该使用std::size_t for循环之类的东西,而不是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的最佳实践是什么?


当前回答

size_t类型是用来指定某个东西的大小,所以使用它是很自然的,例如,获取一个字符串的长度,然后处理每个字符:

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而不是镜头1 ..0)。

其他回答

简短的回答:

几乎没有。使用signed版本ptrdiff_t或非标准的ssize_t。使用函数std::ssize代替std::size。

长一点的回答:

在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要好得多。Ptrdiff_t在32位和64位系统上是长值。

这意味着无论何时与std::容器交互,都必须从size_t转换到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)]);

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

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

这里是Bjarne Stroustrup (c++作者)关于本地化的一些话

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

Size_t是sizeof操作符的结果类型。

size_t用于对数组的大小或索引进行建模的变量。Size_t传达语义:您立即知道它表示字节或索引的大小,而不仅仅是另一个整数。

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

根据定义,size_t是sizeof操作符的结果。创建Size_t是为了引用大小。

你做某事的次数(在你的例子中是10次)与大小无关,那么为什么要使用size_t呢?Int,或者unsigned Int,应该是可以的。

当然,你在循环中对i做什么也是相关的。例如,如果将它传递给一个接受无符号整型的函数,则选择无符号整型。

在任何情况下,我都建议避免隐式类型转换。使所有类型转换显式。

当使用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的值是多少,if表达式都会得到false。 我花了几天时间才意识到这一点(代码太简单了,我没有做单元测试),尽管只花了几分钟就找到了问题的根源。不确定是执行强制转换还是使用零更好。

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

我想听听其他人的意见。

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