【问题标题】:Catching exception without having to throw无需抛出即可捕获异常
【发布时间】:2016-12-08 20:10:22
【问题描述】:

我是 C++ 新手,我来自 Delphi 场景,在该场景中,即使无需声明显式 throw,我也能够捕获异常。看这里:

#include<iostream>
#include<exception>

int main() {

 try {

  int c;
  std::cin >> c;

 } catch(...) {

  std::cerr << "Warning!" << std::endl;
  char xz; std::cin >> xz;
  return 1;

 }

 char z; std::cin >> z;
 return 0;

}

//I return 1 because UNIX OS cares about this, a return != 0 means that Huston we have a problem

我已经看到一些异常(例如被零除)不会被自动捕获,所以我必须自己创建一个throw,它肯定会在我的 try 块中被捕获。

如果您查看上面的代码,当我第一次输入6.7test 时,我应该能够在输出warning! 上看到,但什么也没有。我在 Windows 10 机器上运行。

我知道catch(...) 是通用的,可以肯定地为我提供保护,但为什么它没有捕捉到错误的输入?


注意。我在上面提到了 Delphi,因为如果你看下面的代码,我就能发现错误。

try

 a := StrToInt('6.78');              //conversion error [string->double], a is int
 ShowMessage('a is ' + a.ToString);

except
 on E: Exception do

 ShowMessage('Warning! > ' + e.Message);
 //^ raises "Warning! > '6.78' is not a valid integer value."

end;

为什么我不能用 C++ 产生相同的效果?我知道它们是两种不同的语言,但起初我会说德尔福更好地“处理”异常。例如,它会自动捕获除以零(见下文),而 c++ 不会。

//this raises the "Division by zero" error.
a := 8 div StrToInt('0');

结论。所以问题是:我是否正确地声明了 C++ try-catch?我是否总是必须使用throw确定错误会被捕获,或者我可以在某些时候省略它?

【问题讨论】:

  • catch是不规则动词,第二个from是catch,不是catch。 (抓住,抓住,抓住)
  • 异常在 Delphi 中的工作方式与在 C++ 中的工作方式大致相同。你不能抓住没有抛出的东西。有人必须扔,无论是你还是你正在调用的库。像StrToInt() 这样的函数有明确的raise 语句来在遇到无效输入数据时抛出异常。 Delphi RTL 还响应系统生成的异常(访问冲突、除以零等)并将它们转换为 Delphi 风格的异常。这就是为什么您可以捕获 EAccessViolationEDivByZero 等内容的原因。C++ 不会进行这种转换,但有第三方库可以做到。

标签: c++ delphi exception try-catch


【解决方案1】:

documentation 中所述,您需要在std::cin 上设置异常掩码以使其抛出std::ios_base::failure

#include <iostream>

int main() {
    std::cin.exceptions( std::ios::failbit );
    try {
       int i = 0;
       std::cin >> i;
       std::cout << "i=" << i << std::endl;
    }
    catch(...) {
        std::cerr << "error!" << std::endl;
    }
    return 0;
}

live example

我是否总是必须使用 throw 来确保错误会被捕获,或者我可以在某些时候省略它?

是的,要引发异常,您需要调用 throw。虽然库可能会为您调用 throw 来处理错误情况(包括标准错误),但它可能会抛出什么异常以及何时应该在文档中说明。

【讨论】:

    【解决方案2】:

    std::cin 不会在用户输入无效类型时抛出。

    假设 C++11 及更高版本,行为如下:

    如果提取失败,则将零写入 value 并设置 failbit。如果 提取导致值太大或太小而无法适应 值,std::numeric_limits::max() 或 std::numeric_limits::min() 已写入并设置了故障位标志。

    来自std::basic_istream::operator&gt;&gt;

    要检查输入是否无效,您应该执行以下操作:

    #include <cstdint>
    #include <iostream>
    
    std::int32_t main()
    {
        std::int32_t example;
        std::cin >> example;
    
        if (std::cin.fail())
        {
            std::cout << "Invalid input" << std::endl;
        }
    }
    

    或者你也可以这样做:

    #include <cstdint>
    #include <iostream>
    
    std::int32_t main()
    {
        std::int32_t example;
    
        if (!(std::cin >> example))
        {
            std::cout << "Invalid input" << std::endl;
        }
    }
    

    【讨论】:

    • 您也可以使用bool 转换运算符,例如:if (!(std::cin &gt;&gt; example))
    猜你喜欢
    • 2021-09-02
    • 2013-06-24
    • 1970-01-01
    • 2015-02-13
    • 2011-04-05
    • 2015-09-23
    • 2013-08-02
    • 2018-05-30
    • 2016-02-17
    相关资源
    最近更新 更多