我想在不使用RAII的情况下翻译c ++中的java异常处理。
问题主要涉及最终块。
我找到了一篇使用以下方法的论文:
"一个困难是,finally 子句必须在每次退出 try 块之前执行。一般 try 块的潜在退出数量惊人:正常退出、抛出异常、返回 语句、中断语句、继续语句或无法捕获异常。finally 子句必须在每个子句之前执行(如果它们在 try 块或 catch 块中使用)。例如,以下 Java 代码显示了从 try 块退出的大多数方法:
try {
switch (x) {
case 0: continue next;
case 1: break out;
case 2: throw new TException();
case 3: return(0);
}
} catch (Error e) {
throw(e);
} finally {
System.out.println("finally");
}
然后,我们的解决方案是简单地在所有必须执行它的地方复制 finally 块的文本。如果 finally 块的大小很大,这可能表明 Java 程序员可能希望使其成为一种方法,以便最大限度地减少C++中的代码重复。
以下C++代码显示了必须如何为 try 块的所有出口复制 finally 块:">
try
{
switch(x)
{
case 0:
/* finally clause, continue from try block */
java_lang_System::out->println(_j_toString("finally"));
goto next;
case 1:
/* finally clause, break from try block */
java_lang_System::out->println(_j_toString("finally"));
goto out;
case 2:
/* finally clause, throw exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw(new TException());
case 3:
/* finally clause, return from try block */
java_lang_System::out->println(_j_toString("finally"));
return(0);
}
}
catch(java_lang_Error *e)
{
/* finally clause, caught exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw(e);
}
catch(...)
{
/* finally clause, uncaught exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw;
}
/* finally clause, normal exit from try block */
java_lang_System::out->println(_j_toString("finally"));
我不明白如何在真正的通用程序示例中使用它。交换机中的变量 x 是什么,我应该如何使用它?
GSL 是一个支持 CppCoreGuidelines 的库。指南建议使用 gsl::finally 为此:
#include <gsl/gsl_util>
int main()
{
std::srand(unsigned(std::time(nullptr)));
auto cleanup = gsl::finally([]{
std::cout << "FINALLY it is my turn." << 'n';
});
try
{
if(std::rand() % 2)
throw std::runtime_error("Woopsie 1");
if(std::rand() % 2)
throw std::logic_error("Woopsie 2");
std::cout << "No woopsies on me" << 'n';
}
catch(std::runtime_error const& e)
{
std::cout << e.what() << 'n';
}
catch(std::logic_error const& e)
{
std::cout << e.what() << 'n';
}
}
但是你真的应该转向新类的RAII
设计。这样就不必使用"最后"对象。
注意:请从现实生活中的#include <random>
中获取随机数。
这只是示例代码。要指出的是,java 最终块实际上是在多个点插入的。显示的代码只是一个示例,列出了需要复制 finally 块代码的break
、continue
、return
和throw
- 作为最终代码。
例如:
try {
...
return ...;
...
} finally {
A;
}
会成为
try {
...
{ A; }
return ...;
...
{ A; }
} catch (java_lang_Error *e) {
A;
throw e; // If the catch was not there originally
}
实际上,这就是java字节码中发生的情况。
所以所有离开java try-final的代码都需要复制finally 块的代码。