C ++ Try-Catch语句未捕获异常

时间:2019-05-03 03:14:30

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

我正在用C ++编程一个非常简单的单元测试框架,该框架使用try-catch语句来分析变量。在此示例中,我有一个名为UnitTest的类,分别具有一个公共名称和一个私有成员函数,名称分别为scalars_are_equal()is_equal()。用户必须将str传递给公用函数,该公用函数包含带有测试名称的字符串。用户还必须将value1value2传递给包含两个要相互比较的标量值的public函数。公共函数使用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);
}

由于我不了解的原因,函数catch中的scalars_are_equal()语句未捕获is_equal()函数。起初我以为是因为该函数引发了std::string,但是当我将catch语句从const char更改为std :: string时,它没有任何区别。有人知道为什么这没有捕获到异常吗?

2 个答案:

答案 0 :(得分:7)

您在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;
 }

答案 1 :(得分:0)

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

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

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

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

抛出任何类型的指针都会导致所有权问题,谁负责释放指针?例如,在您的代码中,如果通过调用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";
}

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