我正在用C ++编程一个非常简单的单元测试框架,该框架使用try-catch语句来分析变量。在此示例中,我有一个名为UnitTest
的类,分别具有一个公共名称和一个私有成员函数,名称分别为scalars_are_equal()
和is_equal()
。用户必须将str
传递给公用函数,该公用函数包含带有测试名称的字符串。用户还必须将value1
和value2
传递给包含两个要相互比较的标量值的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时,它没有任何区别。有人知道为什么这没有捕获到异常吗?
答案 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";
}
通常通过引用来捕获异常类型,因为这避免了将它们复制到捕获上下文中,并且还避免了派生类的切片问题。