[英]Iterating over a string with string::size_type vs int
这是我在 TDM-GCC 上使用 C++14 标准(32 位/Windows 10)的代码:
class var
{
private:
vector<int> num;
public:
var(string x)
{
for(int i = x.size()-1; i >= 0; i--) // Notice use of INT
num.push_back(x[i]-'0');
}
};
int main()
{
var num1("232");
return 0;
}
工作得很好,但最佳实践(和几个 SO 答案)说我应该使用string::size_type
而不是int
因为字符串可能比int
可以容纳的长。
现在,当我用string::size_type
替换int
时,会发生一些奇怪的事情; 以下代码可以编译,但是当我执行它时,它什么也不做。 而是 windows 弹出“thisProgram.exe 已停止工作...”对话框,终端突然关闭。 (带有任意大的返回码)
class var
{
private:
vector<int> num;
public:
var(string x)
{
// Everything is same except the following line has string::size_type instead of int
for(string::size_type i = x.size()-1; i >= 0; i--)
num.push_back(x[i]-'0');
}
};
int main()
{
var num1("232");
return 0;
}
那么,使用string::size_type
有什么问题? 这个编译器是特定的吗? 我真的很困惑,因为没有错误消息。
string::size_type
是无符号类型,这意味着它永远不会是负数。 这意味着这种情况:
i >= 0
永远不会是假的。 事实上,当i
低于0
时,它会回绕,并成为string::size_type
的最大可能值。 然后,当您索引x[i]
时,您会调用未定义的行为。
我建议这样写循环:
for(int i = static_cast<int>(x.size()) - 1; i >= 0; i--)
// ...
注意在减 1之前的static_cast
(否则你会遇到空字符串的问题)。
除非你有非常大的字符串,否则长度应该在int
可以处理的范围内。 如果确实需要string::size_type
索引,也可以执行此循环:
auto i = x.size();
while (i-- > 0)
// ...
请注意,这对unsigned
类型是健壮的。 与0
的比较发生在i
递减之前(因此是后递减运算符)。 所以你很好地得到了索引size-1, size-2, ..., 1,0
。 当i
为0
时,比较将失败,然后i
变为大正数这一事实并不重要。
当您编写使用无符号索引和 go 向后的循环时,您必须稍微更改您的习惯用法:
for (std::string::size_type i = x.size(); i > 0; --i)
num.push_back(x[i-1] - '0');
这样你就不必处理从 0 中减去 1 的可能性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.