【问题标题】:How to catch invalid input in c++?如何在 C++ 中捕获无效输入?
【发布时间】:2013-10-31 00:39:00
【问题描述】:

我是一名(有些)经验丰富的 Python 程序员,正在尝试迁移到 C++。我希望能够捕获无效的用户输入。例如,如果一个变量需要一个整数,而用户键入一个字符串,我想捕捉那个错误。在 python 3 中,语法为:

try:
    #block of code you want to run
except ValueError:
    #Block of code to be run if the user inputs an invalid input

在 c++ 中,我读到语法是 Try, catch。我正在尝试这样做,但它不起作用。这是我在 C++ 中的代码:

#include "Calculator.h"
#include <iostream>
#include <exception>

using namespace std;

Calculator::Calculator()
{
}

int Calculator::Calc()
{
    cout << "Enter a number " << endl;
try
{
    cin >> a;
}
catch (logic_error)
{
    cout << "An error has ocurred! You have entered an invalid input!"
}

如何在 C++ 中捕获无效输入?是的,我正在为这个类使用一个头文件。如果您需要这些内容,请告诉我。如果我找到答案,我会继续搜索网络并发布!

【问题讨论】:

  • 我不会使用异常来验证用户输入。我会选择适当的转换方法,比如将字符串转换为 int,并在验证失败时向用户发送消息,然后重新提示输入。

标签: c++ syntax try-catch


【解决方案1】:

您需要#include &lt;limits&gt;

int x;
std::cout << "Enter a number: ";
std::cin >> x;
while(std::cin.fail()) {
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    std::cout << "Bad entry.  Enter a NUMBER: ";
    std::cin >> x;
}
std::cout << "x = " << x << std::endl;

有一个模板给你。

【讨论】:

  • 感谢您的回答,模板正是我想要的!但是,为什么我需要 std:: 在代码中?我目前遇到更多错误,这里是更新的代码:sharetext.org/FMJr
  • @JohnBobSmith 在您的情况下,您不会,因为using namespace std; 行。只要您是using namespace std;,您就可以在我的回答中省略每次出现的std::,但人们会告诉您using namespace std; 是不好的做法。
  • 请看我上面的编辑。我遇到了一些错误,我的代码在sharetext.org/FMJr
  • 这是我在尝试编译上述代码时遇到的错误:错误:'numberic_limits' 未在此范围内声明...错误:预期的主表达式在'>'标记之前.. . 错误:没有匹配函数调用'max{}'
  • @JohnBobSmith using namespace std 与 from Foo import * 一样糟糕,每次导入模块时。最终你会遇到名称冲突、调用错误的函数等。在任何地方使用 std:: 往往太麻烦,所以一个很好的平衡是 using namespace std; 仅在函数内部,或 using std::cin; using std::cout 选择性地将名称带到全局命名空间。
【解决方案2】:

默认情况下,C++ 流不会抛出格式错误的输入:输入错误并不例外。这是正常的。指示输入失败的 C++ 方法是将流置于失败状态,即设置状态标志std::ios_base::failbit。测试错误输入的最简单方法是使用类似

if (in >> value) {
    process(value);
}
else {
    deal_with_input_error(in);
}

处理输入错误通常相当于清除流的状态(只要是故障模式,它根本不会处理实际的流),然后是ignore() 一个或多个违规字符。

如果你真的想得到一个异常,你可以设置一个异常掩码:

in.exceptions(std::ios_base::failbit);
try {
    in >> value;
}
catch (std::ios_base::failure const& ex) {
    // deal with the error
}

只要in.exceptions() &amp; in.rdstate() 在处理状态位或异常掩码的任何成员的末尾非零,就称为引发异常(即调用in.exception(std::ios_base::failbit) 本身可能会引发异常)。抛出的异常类型为std::ios_base::failure。

我建议不要使用 IOStreams 中的异常设施!输入错误是正常的,异常是针对异常错误。在读取值后使用转换为bool 效果很好。

【讨论】:

  • “输入错误是正常的,异常是针对,嗯,异常错误”——所以根据您编程的语言,I/O 故障是否是异常错误?英文短语“异常错误”实际上是否意味着“我对您将非本地控制流用于我认为微不足道的目的”表示强烈反对。等等。
  • 确实,不同的语言对于什么值得提出例外有不同的看法,什么不值得。所以这并不像看起来那么奇怪。
  • @Kylotan:我的主张确实是“异常是针对异常错误/情况”是一个纯粹的循环定义,并没有为程序员提供有用的指导。真正需要的是对例外的利弊进行更详细的评估,这需要经验而不是简单的培训,并且在很大程度上(但不是全部)风格。我并不是要批评 Dietmar 没有在这里解决问题,只是暗示解决问题很简单 ;-) C 程序员可以愉快地建议 C++ 程序员使用 nothrow new,因为分配失败是“正常的”。
  • @SteveJessop:我当然不反对使用例外。例如,处理内存不足是可能发生但很少发生的错误的一个很好的例子。另一方面,在读取文本输入时,很有可能输入没有按预期格式化,从而导致错误。我发现在本地处理预期错误比使用异常更好。 IOStreams 的构造是为了在不处理异常的情况下轻松测试错误。我什至描述了如何在例外情况下使用它们,我只是建议不要使用它。
  • @DietmarKühl:我从来没有真正感觉到发生错误的可能性与您处理它的方式有很大关系,当然除了它是否会影响您的优化方式。正如您所说,您要么想在本地处理错误,要么不想。这不取决于它是每秒发生一次还是每年发生一次,它取决于您的程序的哪个组件能够恢复。因此,您很可能会发现,在解析交互式输入时,您采用的方法与解析文件时不同。后一种情况不太可能在本地恢复,因此异常更有用。
【解决方案3】:

默认情况下,流不会引发异常(可以配置为这样做)。

读取 int 的常用代码是:

int a;
if (std::cin >> a) {
    # OK
} else {
    # error
}

但请确保您知道 &gt;&gt; 在这里实际做了什么。具体来说,C++ 的新手有时会惊讶于它不一定会读一整行。因此,如果您想验证整行输入,或者如果您想重试失败,那么您需要更多代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多