最常见的使用模式std::istringstream
处理用户输入的方法是接受一行文本,然后对其进行处理。这可以避免当输入与您的预期不匹配或无法预测时可能出现的问题。
下面是一个简单的示例,它一次从 STDIN 读取一行,并将其处理为一个命令,后跟一个字符串向量作为参数。
for(std::string line; std::getline(std::cin, line); )
{
std::istringstream iss(line);
std::string command;
if (iss >> command)
{
std::vector<std::string> args;
for (std::string arg; iss >> arg; )
{
args.push_back(arg);
}
std::cout << "Received '" << command << "' with " << args.size() << " arguments\n";
}
else
{
std::cerr << "Invalid input" << std::endl;
}
}
当然,您不需要读取字符串或将内容存储在向量中。这只是为了说明目的。
基本点是避免人们遇到的陷阱,其中最常见的是期望先前的流操作成功。当这个假设不成立时,天真的程序员会发现自己试图解析应该在前一行中传递的内容。
损坏的示例:
#include <iostream>
int main() {
std::string command;
while (std::cin >> command)
{
std::cout << "Got command: " << command << std::endl;
if (command == "foo")
{
// 'foo' expects two integer arguments:
int arg1, arg2;
std::cin >> arg1 >> arg2;
std::cout << command << ": " << arg1 << ", " << arg2 << std::endl;
}
else if (command == "bar")
{
// 'bar' expects one float argument:
float arg1;
std::cin >> arg1;
std::cout << command << ": " << arg1 << std::endl;
}
}
return 0;
}
在上面,假设用户感到困惑并“调用”foo带有一个浮点参数的命令,则下一个命令是有效的bar命令:
foo 42.0
bar 3.14
发生的情况如下:
The foo处理程序将 arg1 读取为 42,然后无法读取下一个参数。流现在有错误。
在该处理程序期间没有对输入进行错误检查,因此现在存在未定义的行为输出值arg2
.
当尝试读取下一个命令时,流已处于错误状态,因此循环终止。
因此,该程序的输出可能如下所示:
Got command: foo
foo: 42, -149017896
修复此问题无需istringstream
这是可能的,但这是一种痛苦。流可能进入错误状态的原因有很多,而清除特定错误状态的错误标志只是为了解决这个问题,这会导致代码丑陋且可能容易出错。您不仅需要清除错误标志,还需要告诉流忽略该行中的任何剩余字符。您可能已经开始阅读next行而不自知。
更稳健的例子:
#include <iostream>
#include <sstream>
int main() {
std::string command;
for (std::string line; std::getline(std::cin, line); )
{
std::istringstream iss(line);
if (!(iss >> command))
continue;
std::cout << "Got command: " << command << std::endl;
if (command == "foo")
{
// 'foo' expects two integer arguments:
int arg1, arg2;
if (iss >> arg1 >> arg2)
{
std::cout << command << ": " << arg1 << ", " << arg2 << std::endl;
}
}
else if (command == "bar")
{
// 'bar' expects one float argument:
float arg1;
if (iss >> arg1)
{
std::cout << command << ": " << arg1 << std::endl;
}
}
}
return 0;
}
现在,与上一个示例相同的输入将给出输出:
Got command: foo
Got command: bar
bar: 3.14
差异是:
Using istringstream
,处理输入的任何错误都不会影响源流,因此前一行的失败不会导致问题。
读取参数时会正确检查字符串流,从而允许可选的错误处理。
如果在某些解析失败后,您决定尝试以不同的方式处理一行输入,那么使用另一个字符串流很容易做到这一点。