c++和Java异常处理的区别
Difference between exception handling in C++ and Java?
在Java中,如果特定的代码行导致程序崩溃,则捕获异常,程序继续执行。
然而,在c++中,如果我有一段导致程序崩溃的代码,比如:
try
{
int x = 6;
int *p = NULL;
p = reinterpret_cast<int*>(x);
*p = 10; // the program crashed here
cout << "x = " << *p << endl;
}
catch(const char* Message)
{
cout << "There is an run-time error";
}
程序仍然崩溃,异常没有被捕获。
那么c++中异常处理的意义是什么呢?我误解什么了吗?导致崩溃的行是对无效指针的解引用。在c++中,这不会抛出异常。相反,它是未定义的行为。
c++中没有空指针异常,不像Java会抛出空指针异常。相反,解引用无效指针将导致未定义的行为。未定义的行为并不总是意味着崩溃,但是如果它崩溃了,你是幸运的。
语言概述:
Finally and RAII
c++和Java之间最显著的区别之一是Java支持finally
语句。不管前面的catch
块中的代码是否执行,finally
块中的代码总是运行。例如:
try
{
}
catch (SomeException e)
{
}
finally
{
//code here is always exectued.
}
finally语句的目的是允许程序员在该点进行清理,即释放套接字,关闭文件句柄等…即使Java运行垃圾收集器,垃圾收集也只应用于内存而不应用于其他资源。仍然有需要手动处理资源的情况。现在c++没有finally
语句,所以该语言的用户被建议坚持RAII原则(资源获取是初始化)Stroustrup对此有一个解释:http://www.stroustrup.com/bs_faq2.html#finally。我更喜欢叫它Resource destruction is deallocation
,但基本上当你的对象超出作用域时,调用析构函数,那么析构函数应该释放对象维护的任何资源。
例如,c++ 11x提供了一个std::unique_ptr来管理:
void foo()
{
std::unique_ptr<T> t(new T)
try
{
//code that uses t
}
catch (...)
{
}
}
通过new
分配的资源将在函数结束时被删除。
捕获所有语句
因为Java中的所有异常都继承自一个公共基类Exception
,如果你想让catch子句捕获任何异常,那么就像这样设置它:
catch (Exception e)
{
//any exception thrown will land here.
}
在c++中,对可以抛出什么没有限制,也没有所有异常的公共基类。标准做法是通过继承std::exception来形成自定义异常类,但语言不强制这样做。相反,有一种特殊的语法用于捕获所有异常:
catch (...)
{
}
未处理的异常这是两种语言表现不同的另一个领域。在c++中,未被捕获的抛出异常将调用std::terminate。std::terminate的默认行为是调用abort,它生成一个SIGABRT,然后整个程序停止。
在Java中,该行为是打印堆栈跟踪并终止发生未捕获异常的线程。然而,由于Java程序员可能会提供UncaughtException处理程序,因此其行为可能与终止线程的默认行为完全不同。
不是所有的崩溃都是由于未处理的异常。对于您的示例,c++标准规定对NULL指针解引用会导致未定义行为。在Windows中,您可以使用结构化异常处理(SEH)来处理导致程序崩溃的问题,而不会抛出c++异常:__try
/__except
/__finally
。在Unix中,可以设置特殊的信号处理程序。
还有,你的代码中有一个错误。const char *
的异常处理程序只会在抛出这种类型的异常时调用。对于标准异常,您应该捕获std::exception
或它的适当子类。要捕获任何c++异常,请使用catch (...)
.
实际上,您可以在c++中捕获系统异常。有一个编译器选项(至少在Visual Studio中)可以让您捕获访问冲突异常(这就是为什么您的程序崩溃)。
Java更加谨慎,因此产生了复杂的错觉。
思考以下内容:
Java:int x[10];
int i = 20;
try
{
int k = x[i];
}
catch (ArrayIndexOutOfBoundsException ex)
{
//will enter here
}
Int c++:
int x[10];
int i = 20;
try
{
if ( i >= 10 )
throw new "Index out of bounds";
int k = x[i];
}
catch (...)
{
//now it will enter here
}
这一切都与您是否希望将更多的事情留给运行时环境(如Java的情况)或您自己想要处理事情有关。c++给了你更多的控制,但是你必须更加注意。
如果不处理异常,你的Java程序也会崩溃——想想看,如果一个方法显式地抛出一个异常,你不能不处理它,因为编译器不允许你这样做。如果不是显式的,你的程序仍然会崩溃,除非被try/catch包围。
如果你问为什么系统异常不能在c++中处理,我已经回答了:它们可以,只是在默认情况下,这是关闭的。
在任何语言中,异常的意义都是或者应该是要处理的异常情况。但仍有一些情况你可以做出合理的解释关于全局程序状态的假设,以及可能的恢复。编程错误通常意味着您不能对全局程序状态,并且必须尽快终止代码可能的,执行最少的额外代码(因为你不知道什么))。
在Java中,几乎所有的事情都是通过异常来报告的。从常见的,预期的错误("未找到文件")打开文件)导致严重的内部错误(java.lang.VirtualMachineError)。c++给了你选择:如果你检测到编码错误(断言失败),您可以中止该进程立即(通常比在一个未知的地方瞎混更合适)状态);如果"错误"是通常会发生在日常操作("文件未找到"),可以测试状态,或者使用返回代码(同样,通常比异常更合适)。对于一个这两种情况之间的数量(例如内存不足),c++使用例外。
当然,在给定的应用程序中,什么是最合适的是不同的:当然,在某些情况下,"未找到文件"是例外情况(例如,如果该文件是应用程序的一部分,没有它就不能运行),并且需要一个例外。类似地,在特定情况下,空指针可以用于控制程序逻辑(if ( ptr == NULL ) ...
)或对应一个例外情况(if ( ptr == NULL ) throw ...
);在在其他情况下,空指针是编程错误( assert( ptr != NULL)
)。
- c++和Java都有try和catch块,但是Java有一个新的块,总是在try和catch之后执行。Java只抛出对象,但c++抛出数据(原语和指针&对象)。
- c++有catch(…){}捕获所有类型的异常,Java有catch(exception e){}捕获所有类型的异常。
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Firebase C++VS2018 SDL2-在Firebase::app::create(..)上执行异常处理
- 使用 stoi 功能进行异常处理
- 子系统中的异常处理:本机
- 与异常处理程序中的操作员<<不匹配
- 数组 C++ 上的异常处理程序
- 异常处理:如果用户输入不是三个特定字符之一
- C++ 异常处理错误输出
- 视觉 std::矢量无异常:警告 C4530:使用了C++异常处理程序,但未启用展开语义.指定 /EHsc
- C++交换机状态异常处理
- 在字符串类上的成员函数和out_of_range异常处理
- 奇怪的消息 (_Base_bitset::_M_do_to_ulong) 从溢出异常处理程序中打印出来
- 执行视觉工作室异常处理模式
- 为什么隐式转换在异常处理中从派生到基?
- C++执行期间的类成员函数错误/异常处理
- C++ 中未处理的异常处理程序
- 用户定义的异常处理
- 使用try-Catch异常处理程序和if-else条件检查之间的区别
- c++和Java异常处理的区别