Answers:
一个好的经验法则是,您需要在循环条件下将其与自然std::size_t
本身进行比较的任何内容。
std::size_t
是任何sizeof
表达式的类型,并保证能够表达C ++中任何对象(包括任何数组)的最大大小。通过扩展,它也保证对任何数组索引都足够大,因此它是数组上逐个索引循环的自然类型。
如果您只计算一个数字,那么使用保存该数字的变量类型或一个int
或unsigned int
(如果足够大)的类型可能会更自然,因为这些对于机器而言应该是自然大小。
ssize_t
用于签名的值。
size_t
是sizeof
运算符的结果类型。
使用size_t
变量数组中的模型的大小或指数。size_t
传达了语义:您立即知道它代表一个以字节为单位的大小或一个索引,而不仅仅是另一个整数。
另外,使用size_t
字节表示大小有助于使代码具有可移植性。
该size_t
类型用于指定内容的大小,因此很自然地使用它,例如,获取字符串的长度然后处理每个字符:
for (size_t i = 0, max = strlen (str); i < max; i++)
doSomethingWith (str[i]);
你也必须注意,当然边界条件,因为它是一个无符号类型。因为最大通常比较大(虽然它在高端产品的界限通常不是重要的是可以到那里)。大多数人只是将an 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
)。
strlen
循环的每次迭代都是一种不好的做法。:)您可以执行以下操作:for (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
“ goes to”运算符(实际上请参见stackoverflow.com/questions/1642028/…),但这实际上是一个巧妙的技巧。已将您的建议纳入答案。
if (i == 0) break;
在for循环的末尾做一个简单的事情吗(例如,for (size_t i = strlen(str) - 1; ; --i)
。(虽然我更喜欢您,但是我想知道这是否也可以工作)。)
根据定义,size_t
是sizeof
运算符的结果。size_t
是为了参考尺寸而创建的。
您做某事的次数(在您的示例中为10)与尺寸无关,那么为什么要使用size_t
?int
或unsigned int
应该可以。
当然i
,循环内的处理也很重要。unsigned int
例如,如果将其传递给需要的函数,请选择unsigned int
。
无论如何,我建议避免隐式类型转换。使所有类型转换都明确。
几乎从不
每当您需要在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
是long
在32个64位系统。
这意味着,当您与不太漂亮的std :: containers交互时,始终必须在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(const auto& d : data) {
[...]
}
这里是一些从Bjarne的Stroustrup的(C ++的作者)的话去本地
对于某些人来说,STL中有符号/无符号的设计错误足以说明原因,不要使用std :: vector,而是使用自己的实现。
for(int i = 0; i < get_size_of_stuff(); i++)
。现在,可以肯定,您可能不想做很多原始循环,但是-来吧,您也可以使用它们。
x + 1 < y
等价于x < y - 1
,但它们不是不带正整数的整数。当事物被认为是等效的时,这很容易引入错误。
使用std :: size_t索引/计数C样式数组。
对于STL容器,您将拥有(例如)vector<int>::size_type
,应将其用于索引和计数向量元素。
实际上,它们通常都是无符号的整数,但是不能保证,特别是在使用自定义分配器时。
std::size_t
通常是unsigned long
(在64位系统上为8字节),而不是unisgned int
(4字节)。
size_t
但是,C样式的数组不会被索引,因为索引可以是负数。但是size_t
,如果一个人不想变成负数,就可以使用自己的数组实例。
+
对指针使用运算符,因此似乎ptrdiff_t
是用于索引的一种。
vector<T>::size_type
(以及所有其他容器的同上),它实际上是无用的,因为可以有效地保证它是size_t
-类型定义为Allocator::size_type
,对于容器的限制请参见20.1.5 / 4-特别是size_type
必须是size_t
并且difference_type
必须是ptrdiff_t
。当然,默认值std::allocator<T>
可以满足这些要求。因此,只使用较短size_t
的部分,而不必理会其余部分:)
使用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
我想要其他人的评论。
(int)(i - 7)
是一个强制转换为int
之后int(i) - 7
的下溢,而不是由于您先转换i
为int
,然后减去,所以不是下溢7
。另外,我发现您的示例令人困惑。
各种库返回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。
size_t是无符号整数类型,可以表示系统上的最大整数。仅在需要非常大的数组,矩阵等时才使用它。
某些函数返回size_t,并且如果您尝试进行比较,则编译器会警告您。
为避免这种情况,请使用适当的带符号/无符号数据类型,或者只是简单地进行类型转换以快速破解。
size_t是unsigned int。因此,无论何时您想要unsigned int都可以使用它。
我想指定数组的大小,计数器等时使用它
void * operator new (size_t size); is a good use of it.
size_t
可能是一个无符号的64位整数,而在32位计算机上,它只是一个32位的无符号整数。
size_t
时机可能会导致安全漏洞。