带有size_t循环变量的后向循环

backward loop with size_t loop variable

本文关键字:循环 变量 带有 size      更新时间:2023-10-16

以下是代码定义的行为,我的意思是I——当I为0时,它将始终是size_t表示的最大无符号int,对吗?那么在我的代码中使用它完全安全吗?

size_t NPOS = -1;
for(size_t i = vec.size()-1; i!= NPOS; i--)

这是一个使用绝妙的go-to运算符的经典场景:

for (size_t i = vec.size(); i --> 0; )

在类std::basic_string中,静态数据成员npos的定义方式如下

static const size_type npos = -1;

考虑成员函数size()的返回值的类型为size_type。所以你的代码是有效的

size_t NPOS = -1;
for(size_t i = vec.size()-1; i!= NPOS; i--)

条件是表达式vec.size()-1的值可以存储在类型size_t

所以更有效的代码将看起来像

for ( std::vector<T>::size_type i = vec.size()-1; i != std::vector<T>::npos; i-- )

尽管我会用以下方式写循环

for ( std::vector<T>::size_type i = vec.size(); i != 0;  )
{
   //...
   // using expression vec[--i]
   // or
   //  --i
   // vec[i]
   //...
} 

从技术上讲,它是有效的,因为-1到无符号类型保证产生尽可能大的值,从0开始递减。但事实并非如此我会考虑好的做法。如果你只想迭代在一个矢量上反向:

for ( auto current = vec.rbegin(); current != vec.rend(); ++ current ) {
    //      Do something with *current
}

如果出于某种原因你确实需要索引:

int i = vec.size();
while ( i != 0 ) {
    -- i;
    //      Do something with vec[i]
}

这个循环要干净得多,并且避免了未签名的任何问题类型包装(尽管如果您需要索引意味着你需要它作为一个算术值,所以你应该避免以无符号类型开头)。

对于给定的整数类型T,所有这些都是相同的值,有符号或无符号:

T a = -1;
T b = 0 - 1;
T c = 0; c = c - 1;
T d = 0; d --;
T e = 0; -- e;
assert(a == b);
assert(a == c);
assert(a == d);
assert(a == e);

这涵盖了您在代码片段中的所有用法。整数的内部表示并不重要。有符号-1转换为类似的无符号整数的最大值这一事实很有趣,但并不直接重要。如果算术不起作用,则上述情况成立。