try-catch
块是否会捕获分段错误错误?
我正在使用下面给出的函数读取文本文件,但有时文件为空,程序崩溃。我希望程序继续运行,并在此文件为空或正在使用时提供另一个文件。
Path2D read_gesture(const char* filename)
{
Path2D path;
//MultiStrokeGesture MultiStrokes;
vector<string> text_file;
int no_of_paths=0;
std::ifstream ifs(filename);
for (std::string line; std::getline(ifs, line); )
{
no_of_paths=no_of_paths+1;
double a, b;
stringstream ss(line);
if (!(ss >> a >> b)) {cout<<"wrong format"<<endl;}
std::cout << "You said, " << a << ", " << b << ".\n";
path.push_back(Point2D(a,b));
}
cout<<"saving gesture"<<endl;
return path;
}
我尝试过类似的事情:
Path2D path;
try
{
path=read_gesture("test.txt");
}
catch(int e)
{
path=read_gesture("test2.txt");
}
但程序仍然崩溃。问题可能是什么?
catch
中调用的文件与try
中的文件不同,这是一个错字。答案 0 :(得分:28)
C ++ try-catch
块只处理C ++异常。像分段错误这样的错误是较低级别的,try-catch会忽略这些事件,并且行为与没有try-catch块的行为相同。
答案 1 :(得分:9)
try / catch仅捕获C ++异常。只有当您的程序执行非法操作并调用未定义的行为时,才会发生分段错误。
请记住,未定义的行为可以以不同的方式显示,包括不崩溃。你很幸运让你的程序崩溃,告诉你需要修复的东西,但程序可能不会崩溃;你不能让你的后备代码取决于崩溃。
适当的做法是不要像处理异常那样处理崩溃,而是确保即使输入不符合预期,程序也不会执行任何非法操作。在这种情况下,您需要更改代码,以便知道文件何时为空并需要提供另一个。
通常有一种方法可以处理分段错误,但它并不打算进行您正在寻找的那种恢复。机制是信号。您可以安装一个信号处理程序,该信号处理程序在引发指定信号时执行,例如SIGSEGV用于分段错误。但是,除非您使用std :: raise显式提升它,否则不要求实际发生这样的信号。此外,当信号由实现引发时,您可以在信号处理程序中执行的操作受到严格限制;
如果信号发生而不是因为调用中止或 提升函数,如果信号处理程序引用,则行为未定义 除了通过分配a之外的任何具有静态存储持续时间的对象 声明为volatile sig_atomic_t或信号的对象的值 handler会调用除标准库以外的任何函数 中止函数,_Exit函数或带有的信号函数 第一个参数等于对应于信号的信号编号 这导致了处理程序的调用。此外,如果这样的电话 信号函数导致SIG_ERR返回,errno的值 是不确定的。
答案 2 :(得分:4)
如果您的程序存在分段错误,并且这不是您故意执行的操作,那么您无需执行任何操作。你无法抓住它,即使你可以,你也无法继续该计划。
此外,以下代码存在一个非常严重的问题:
try {
path=read_gesture("test.txt");
}
catch(int e) {
path=read_gesture("test.txt");
}
“如果一开始你没有成功,再试一次”对人类来说是一个很好的座右铭,但计算机每次都以完全相同的方式做事。如果操作失败,除非是瞬时故障(例如网络故障),再次尝试是徒劳的。
您唯一的选择是编写正确的程序,因为正确的程序不会出现段错误。如果你想找到段错误,你可以在Valgrind或GDB中运行程序,这两个程序都应该给出回溯线索(但是你必须用头来找到你程序中的真正错误)。
另一种选择是使用一种不会出现段错误的语言,如Java,C#,Python,Ruby,Haskell,JavaScript,Go,Rust,或者几乎所有使用的语言,除了C或C ++。
脚注:这有点简化,因为它实际上可以编写正确的程序来获得分段错误。但是,这不是你正在做的事情。
答案 3 :(得分:1)
您可以尝试添加一点测试以查看ifs是否有效:
#include <iostream>
#include <fstream>
int main(int argc, char * argv[]){
std::ifstream ifs( "notExists" );
if( ifs.is_open()) {
char line[1024];
while(! ifs.fail() && ifs.getline( line, sizeof( line ))) {
std::cout << line << std::endl;
}
}
else {
std::cout << "file doesn't exists." << std::endl;
}
std::cout << "done." << std::endl;
return 0;
}
该程序运行并输出:
file doesn't exists.
done.
bool std::ifstream::is_open();
有关详细信息,请参阅getline全局函数,如果失败,则在此处设置一些未检查的位。
通过修改内部状态标志来发出错误信号:
此外,在任何这些情况下,如果使用is的成员函数ios :: exceptions设置了适当的标志,则会抛出ios_base :: failure类型的异常。
答案 4 :(得分:1)
首先,你可以(读应该)以一种永远不会产生例如分段错误的异常的方式编写你的代码。
首先,你应该检查所有可能无效的指针(例如,类的用户调用的类的公共函数可能会收到一些无效的指针,但内部实现可能会假设已经检查了指针)。
其次,您应检查可能失败的功能的结果,例如malloc
可能无法分配内存或您尝试打开的文件可能被删除或您无权打开它或甚至在打开后它的数据可能无效,因此您应该检查您的行动结果。 C ++中的这个过程比C容易得多,例如new
在失败时抛出异常,或者stream
在任何错误或eof的情况下都可以转换为false
。
但要回答你的问题一般catch
阻止只捕获类型异常,但在某些编译器catch(...)
中也可能捕获异常,例如分段错误,甚至将这些异常转换为C ++异常,例如在windows平台下您可以使用_set_se_translator
为类似于C ++异常的异常设置全局转换程序,使用MSVC,您也可以使用/EHa
编译程序,以便在catch(...)
中捕获这些异常但是所有这些都是特定于特定平台或编译器的扩展,因此正确编写代码并且从不考虑解决问题的方法。
答案 5 :(得分:0)
尝试检查是否可以使用catch(...){cout<<'catched';}
也可以尝试这一行,这样就可以防止推错格式点:
if (!(ss >> a >> b)) {cout<<"wrong format"<<endl; continue;}