【问题标题】:C++ Try-Catch Statement not catching an exceptionC++ Try-Catch 语句未捕获异常
【发布时间】:2019-05-03 03:14:30
【问题描述】:

我正在用 C++ 编写一个非常简单的单元测试框架,它使用 try-catch 语句来分析变量。在此示例中,我有一个名为 UnitTest 的类,其中一个公共成员函数和一个私有成员函数分别名为 scalars_are_equal()is_equal()。用户必须将str 传递给公共函数,其中包含一个带有测试名称的字符串。用户还必须将value1value2 传递给包含两个要相互比较的标量值的公共函数。公共函数使用try 语句并将数据传递给私有函数,在该私有函数中评估两个变量以查看它们是否匹配。如果值匹配,则返回调用函数,在该函数中将一条消息打印到屏幕上,让用户知道测试通过。如果值不相等,则私有函数应抛出分配给字符串msg 的异常,而公共函数应捕获此异常。课程附在下面。这些函数被编写为模板函数,因此用户可以选择比较整数、浮点数和双精度数,即使浮点运算可能意味着一个数字的两个版本并不完全相同。

class UnitTest
{
public:
    template <class type1, class type2>
    void scalars_are_equal(std::string str, const type1 &value1, const type2 &value2);
private:
    template <class type1, class type2>
    void is_equal(const type1 &value1, const type2 &value2, std::string str);
};
// ================================================================
// ================================================================
// UnitTest PUBLIC member functions
template <class type1, class type2>
void UnitTest::scalars_are_equal(std::string str, const type1 &value1,
                             const type2 &value2)

{
    unsigned long remain;
    remain = 60 - str.length();
    try {
        is_equal(value1, value2, str);
        std::cout << str + std::string(remain, '.') +
        std::string("PASSED") << std::endl;
    }
    catch (const char* msg) {
        std::cout << msg << std::endl;
    }
}
// ----------------------------------------------------------------

template <class type1, class type2>
void UnitTest::is_equal(const type1 &value1, const type2 &value2,
                        std::string str)
{
    if (value1 != value2) {
        unsigned long remain;
        remain = 60 - str.length();
        std::string msg = str + std::string(remain, '.') + " FAILED";
        throw msg;
    }

}

在这种情况下,主程序看起来像;

#include <iostream>
#include <string>
#include <vector>
#include <array>

#include "unit_test.hpp"

int main(int argc, const char * argv[]) {
    UnitTest q;
{    // Test to see if code catches unequal scalars
    float a, b;
    a = 20.0;
    b = 30.0;
    std::string c ("Scalars_Unequal_Test");
    q.scalars_are_equal(c, a, b);
}

由于我不明白的原因,函数scalars_are_equal() 中的catch 语句没有捕获is_equal() 函数。起初我以为可能是因为函数抛出了std::string,但是当我将catch 语句从const char 更改为std::string 时,并没有什么不同。有谁知道为什么这没有捕捉到异常?

【问题讨论】:

  • 你真的不需要show the issue的所有代码。提示:std::string 不是 const char *
  • 但是当我将 catch 语句从 const char 更改为 std::string 时,它没有任何区别 -- 请发布此尝试。
  • 能够重现const char *,但这是预期的行为。无法重现 std::string 版本。我必须对代码进行编译以使其编译的更改可能已经改变了一些东西。我们可以得到minimal reproducible example 自己试用吗?
  • 在一种不相关的注释上:这并不是 try and catch 的真正用途。 Try and catch 用于捕获错误并从错误中恢复,而不是来回传递数据,这就是您正在做的事情。
  • @Chipster 我想说为单元测试失败抛出异常是很合理的,这是许多单元测试框架的工作方式

标签: c++ try-catch c++17


【解决方案1】:

您在 UnitTest::is_equal() 中抛出 std::string 而不是 char*。

std::string msg = str + std::string(remain, '.') + " FAILED";
throw msg;

所以你必须抓住一个字符串:

catch (std::string& msg) {
    std::cout << msg << std::endl;
}

重要的旁注:不要抛出 std::string 或类似的,而是从 std::exception 或您自己的异常基类派生的类。例如:

 std::string msg = str + std::string(remain, '.') + " FAILED";
 throw std::runtime_error(msg);
 [...]
 catch (std::runtime_error& e) {
    std::cout << e.what() << std::endl;
 }

【讨论】:

    【解决方案2】:

    您的 catch 中的类型必须与您要抛出的类型(或该类型的父类)相同。

    您的代码基本上可以归结为

    try
    {
      throw std::string( "test" );
    }
    catch ( const char* msg )
    {
    }
    

    您正在抛出 std::string 但捕获 const char* 因此不会捕获异常。您需要直接抛出 "test" 而不将其包装在 std::string 中,或者将您的捕获更改为 std::string&amp;

    抛出任何类型的指针都会导致所有权问题,谁负责释放指针?例如,在您的代码中,如果您通过调用throw msg.c_str()“修复”问题,则msg 字符串将在到达您的catch 块之前被销毁,并且char* 指针将无效,以修复您必须动态分配一个新的char 数组并将msg 复制到其中,catch 块将需要delete 数组但无法知道它需要。

    语言允许抛出任意类型,但建议从std::exception 派生所有抛出类型,这样您就可以编写如下代码并能够捕获代码抛出的所有异常。

    try
    {
      // lots of code including calling third party libraries
    }
    catch ( std::exception& ex )
    {
      std::cout << "uncaught exception: " << ex.what() << "\n";
    }
    

    异常类型通常通过引用来捕获,因为这样可以避免将它们复制到捕获上下文中,并且还避免了派生类的切片问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      • 2017-11-09
      • 2020-02-28
      • 1970-01-01
      相关资源
      最近更新 更多