5

假设我有两个在 C++ 中处理的继承层次结构。一个继承自std::exception(新层次结构),另一个继承自Exception(遗留 C++ Builder VCL 基异常类)。如果我调用可能引发任何类型异常的代码,我必须编写如下代码:

try {
    // do stuff....
    Function1();
    Function2();
} catch (std::exception &ex) {
    std::cout << "STL exception caught: " << ex.what() << std::endl;
} catch (Exception &ex) {
    std::cout << "Legacy exception caught: " << ex.Message.c_str() << std::endl;
} catch (SomeOtherVendorLibraryException &ex) {
    // etc.
}

问题是每个调用者都需要拥有所有这些 catch 子句来尝试获取最后一种类型的异常,因为 C++ 没有一个真正的、强制的异常基类,您可以将其用作包罗万象的System.Exception类(例如 C# 中的类)。(catch (...)这是一个非首发,因为你没有办法知道你捕获了什么,并且一些危险的系统异常,如访问冲突,也可能被捕获,最好不要陷入困境。)

我想将这些“遗留”异常包装到std::exception层次结构中的一个类中。这种将第 3 方异常包装到您自己的异常系统中的概念并非完全没有先例。例如,.NET Framework 包含了其他系统中的大量错误(例如COMException)。理想情况下,我希望看到这样的东西:

class LegacyException : public std::runtime_error {
public:
    // construct STL exception from legacy exception
    LegacyException(const Exception &ex) : std::runtime_error(ex.Message.c_str()) {}
};

try {
    // In reality, this throw will happen in some function we have no control over.
    throw Exception("Throwing legacy exception!");
} catch (std::exception &ex) {
    // Ideally, the compiler would use the LegacyException constructor
    // to cast the thrown Exception to a LegacyException, which ultimately
    // inherits from std::exception.
    std::cout << ex.what() << std::endl;
}

可以理解的是,异常永远不会被捕获——它会要求编译器使用相当多的魔法来捕获它。

是否有可能与上述类似的解决方案来包装遗留异常并实现这些目标?

  • 一个“catch”子句或类似子句,因此一般异常处理逻辑只需要编写一次。
  • 从一种异常类型转换为另一种异常类型的逻辑必须集中。
  • 尽可能避免使用宏。
  • 不使用 lambda 函数。
4

1 回答 1

2

在使用 BC++Builder 之后,我遇到了同样的问题,而宏似乎是当时唯一的解决方案。

“更清洁”(嗯...)解决方案可能是“双重尝试捕获”:内部尝试捕获将您的遗留异常转换为标准类,而外部实际处理异常。

我手头没有代码(已经好几年了),但基本上可以归结为:

#define DTRY  try { try
#define DCATCH catch (Exception& e) { throw LegacyException(e); } } catch

DTRY {
   ...
}
DCATCH(std::exception& e) {
    // handle the exception
}

是的,我知道这很丑,但是当我与 Borland 合作时,我没有发现更好的东西。事实是,当时 Borland 非常不标准,我不知道它是如何演变的,也许你现在可以做得更好。无论如何,希望这会有所帮助。

于 2013-03-28T22:01:32.417 回答