在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 ++中的异常处理有什么意义呢?我误解了什么吗?
答案 0 :(得分:31)
崩溃的行取消引用无效指针。在C ++中,这不会引发异常。相反,它是未定义的行为。
没有null pointer exception in C++这样的东西,不像Java会抛出空指针异常。而取消引用无效指针将导致未定义的行为。未定义的行为并不总是意味着崩溃,但是如果它崩溃你很幸运。
C ++和Java之间最重要的区别之一是Java支持finally
语句。无论前面的finally
块中的代码是否被执行,catch
块中的代码总是运行。例如:
try
{
}
catch (SomeException e)
{
}
finally
{
//code here is always exectued.
}
finally语句的目的是允许程序员在那时清理,即释放套接字,关闭文件句柄等......即使Java运行垃圾收集器,垃圾收集只适用于内存而不适用于其他资源。您仍然需要manually dispose of resources。现在C ++没有finally
语句,因此建议该语言的用户遵守RAII原则(Resouce Acquisition is Initialization)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
分配的资源。
因为如果希望catch子句捕获任何异常,Java中的所有异常都从公共基类Exception
继承,那么将其设置为:
catch (Exception e)
{
//any exception thrown will land here.
}
在C ++中,对于可以抛出的内容没有限制,并且没有针对所有异常的公共基类。标准做法是通过继承std :: exception来形成自定义异常类,但该语言不强制执行此操作。相反,有一种特殊的语法可以捕获所有异常:
catch (...)
{
}
这是语言行为不同的另一个领域。在C ++中,未捕获的抛出异常将调用std :: terminate。 std :: terminate的默认行为是调用abort,生成SIGABRT,整个程序停止。
在Java中,行为是打印堆栈跟踪并终止未捕获异常发生的线程。但是,由于Java程序员可能提供UncaughtException处理程序,因此行为可能与终止线程的默认行为完全不同。
答案 1 :(得分:8)
并非所有崩溃都是由于未处理的异常造成的。对于您的示例,C ++标准说取消引用NULL指针会导致未定义的行为。在Windows中,您可以处理导致程序崩溃的问题,而不会使用structured exception handling(SEH)抛出C ++异常:__try
/ __except
/ __finally
。在Unix中,您可以设置特殊的signal处理程序。
此外,您的代码中存在错误。只有在抛出此类型的异常时,才会调用const char *
的异常处理程序。对于标准异常,您应该捕获std::exception
或它的相应子类。要捕获任何C ++异常,请使用catch (...)
。
答案 2 :(得分:1)
实际上,您可以在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 ++中处理,我已经回答:他们可以,就是这样,默认情况下,这是关闭的。
答案 3 :(得分:1)
任何语言的例外都是或应该是处理的 例外情况。但仍然可以让你合理的情况 关于全球计划状态的假设,并可能恢复。 编程错误通常意味着您不能做任何假设 全局程序状态,并且必须尽快终止代码 可能,执行最少的额外代码(因为你不知道什么 它会这样做。
在Java中,几乎所有内容都是通过异常进行报告的。 一切都来自常见的预期错误(尝试时“找不到文件”) 打开文件)以发现严重的内部错误 (java.lang.VirtualMachineError)。 C ++为您提供了选择:如果您 检测到编码错误(断言失败),可以中止该过程 立即(通常比在未知的情况下顽固更合适 州);如果“错误”是通常会发生的事情 日常操作(“找不到文件”),您可以测试状态,或使用 返回代码(再次,通常比异常更合适)。为一个 C ++使用的两种情况之间的情况(例如,内存不足) 异常。
当然,在给定的应用程序中最合适的是:
肯定存在“未找到文件”的例外情况(例如,如果
该文件是应用程序的一部分,没有它就无法运行),和
保证例外。同样,在特定情况下,空指针可以
用于控制程序逻辑(if ( ptr == NULL ) ...
)或
对应一个例外情况(if ( ptr == NULL ) throw ...
);在
在其他情况下,空指针是编程错误
(assert( ptr != NULL)
)。
答案 4 :(得分:0)