在 C++ 中捕获分段错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12978234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Catch Segmentation fault in c++
提问by rajat
Does a try-catch
block catch segmentation fault errors?
try-catch
块是否捕获分段错误错误?
I am reading a text file using the function given below but sometimes the file is empty and the program crashes. I would like the program to continue running and provide another file when this file is empty or in use.
我正在使用下面给出的函数读取文本文件,但有时文件为空并且程序崩溃。我希望程序继续运行并在此文件为空或正在使用时提供另一个文件。
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;
}
I tried something like:
我试过类似的东西:
Path2D path;
try
{
path=read_gesture("test.txt");
}
catch(int e)
{
path=read_gesture("test2.txt");
}
but the program still crashes. What might the problem be?
但程序仍然崩溃。可能是什么问题?
- A little correction, the file called in
catch
was not same as that oftry
, that was a typo.
- 稍微更正,调用的文件与 的文件
catch
不同try
,这是一个错字。
回答by
C++ try-catch
blocks only handle C++ exceptions. Errors like segmentation faults are lower-level, and try-catch ignores these events and behaves the same as if there was no try-catch block.
C++try-catch
块只处理 C++ 异常。诸如分段错误之类的错误是较低级别的,而 try-catch 会忽略这些事件,其行为与没有 try-catch 块一样。
回答by bames53
try/catch only catches C++ exceptions. Segmentation faults will only occur when your program does something illegal and invokes undefined behavior.
try/catch 只捕获 C++ 异常。分段错误仅在您的程序执行非法操作并调用未定义行为时才会发生。
Remember that undefined behavior can manifest in different ways, including not crashing. You're lucky to have your program to crash to inform you that there's something you need to fix, but the program may not crash; you can't make your fallback code depend on the crash.
请记住,未定义的行为可以以不同的方式表现出来,包括不崩溃。你很幸运,你的程序崩溃了,通知你有一些事情你需要修复,但程序可能不会崩溃;你不能让你的后备代码依赖于崩溃。
The appropriate thing to do is not to handle the crash like you would an exception, but instead to ensure that your program does not do anything illegal even when the input is not what you expect. In this case you need to change your code so that you know when the file is empty and need to provide another one.
正确的做法不是像处理异常那样处理崩溃,而是确保即使输入不是您所期望的,您的程序也不会执行任何非法操作。在这种情况下,您需要更改代码,以便知道文件何时为空并需要提供另一个。
There usually is a way to handle segmentation faults, but it's not intended to do the kind of recovery you're looking for. The mechanism is signals. You can install a signal handler which executes when a specified signal is raised, such as SIGSEGV for segmentation faults. However there's no requirement that such a signal will actually occur except when you explicitly raise it with std::raise. Also the things you can do in a signal handler when the signal is raised by the implementation are severely restricted;
通常有一种方法可以处理分段错误,但它并不打算进行您正在寻找的那种恢复。机制是信号。您可以安装一个信号处理程序,该处理程序在引发指定信号时执行,例如用于分段错误的 SIGSEGV。但是,除非您使用 std::raise 显式引发它,否则不要求实际发生这样的信号。此外,当信号由实现引发时,您可以在信号处理程序中执行的操作受到严格限制;
If the signal occurs other than as the result of calling the abort or raise function, the behavior is undefined if the signal handler refers to any object with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t, or the signal handler calls any function in the standard library other than the abort function, the _Exit function, or the signal function with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler. Furthermore, if such a call to the signal function results in a SIG_ERR return, the value of errno is indeterminate.
如果信号不是作为调用 abort 或 raise 函数的结果而发生的,则如果信号处理程序引用任何具有静态存储持续时间的对象,而不是通过为声明为 volatile sig_atomic_t 的对象或信号分配值,则行为未定义处理程序调用标准库中除 abort 函数、_Exit 函数或信号函数以外的任何函数,其第一个参数等于引起处理程序调用的信号对应的信号编号。此外,如果对信号函数的此类调用导致 SIG_ERR 返回,则 errno 的值是不确定的。
回答by Dietrich Epp
If your program has a segmentation fault, and it's not something you did on purpose, then there's nothing you can do about it. You can't catch it, and even if you could, you can't continue the program afterwards.
如果您的程序存在分段错误,并且这不是您故意做的,那么您将无能为力。你赶不上它,即使你能赶上,你也不能在之后继续程序。
Furthermore, the following code has a very serious problem:
此外,下面的代码有一个非常严重的问题:
try {
path=read_gesture("test.txt");
}
catch(int e) {
path=read_gesture("test.txt");
}
"If at first you don't succeed, try again" is a good motto for humans, but computers do things the exact same way every time. If an operation fails, unless it's a transient failure (such as a network failure), trying again is futile.
“如果一开始你没有成功,那就再试一次”对人类来说是一句很好的格言,但计算机每次都以完全相同的方式做事。如果操作失败,除非是暂时性故障(例如网络故障),否则再试是徒劳的。
Your only choice is to write a correct program,because correct programs do not segfault. If you want to find the segfault, you can run the program in Valgrind or GDB, both of which should give backtraces full of clues (but you have to use your head to find the true error in your program).
您唯一的选择是编写正确的程序,因为正确的程序不会出现段错误。如果你想找到段错误,你可以在 Valgrind 或 GDB 中运行程序,这两者都应该给出充满线索的回溯(但你必须用你的头脑来找到你程序中的真正错误)。
The other alternative is to use a language which does not get segfaults, like Java, C#, Python, Ruby, Haskell, JavaScript, Go, Rust, or almost every language used these days except C or C++.
另一种选择是使用不会出现段错误的语言,如 Java、C#、Python、Ruby、Haskell、JavaScript、Go、Rust 或几乎所有这些天使用的语言,除了 C 或 C++。
Footnote:This is a bit of a simplification, since it is actually possible to write correct programs that get segmentation faults. However, that's not what you're doing.
脚注:这有点简化,因为实际上可以编写出现分段错误的正确程序。然而,这不是你在做什么。
回答by Aubin
You can try to add a little test to see if ifs is valid:
您可以尝试添加一个小测试,看看 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;
}
This program runs and output:
该程序运行并输出:
file doesn't exists.
done.
bool std::ifstream::is_open();
bool std::ifstream::is_open();
See the getlineglobal function for more information, if it fail, it set some bit not checked here.
有关更多信息,请参阅getline全局函数,如果失败,则在此处设置一些未检查的位。
Errors are signaled by modifying the internal state flags:
通过修改内部状态标志来发出错误信号:
- eofbit: The end of the source of characters is reached during its operations.
- failbit: No characters were extracted because the end was prematurely found.Notice that some eofbit cases will also set failbit.
- badbit: An error other than the above happened.
- eofbit:在其操作期间到达字符源的末尾。
- failbit:没有提取字符,因为过早地找到了结尾。注意一些eofbit情况也会设置failbit。
- badbit:发生了上述以外的错误。
Additionally, in any of these cases, if the appropriate flag has been set with is's member function ios::exceptions, an exception of type ios_base::failure is thrown.
此外,在任何这些情况下,如果使用 is 的成员函数 ios::exceptions 设置了适当的标志,则会抛出 ios_base::failure 类型的异常。
回答by BigBoss
First of all you can(read should) write your code in a way that it never generate exceptions such as segmentation fault.
首先,您可以(阅读应该)以永不产生异常(例如分段错误)的方式编写代码。
First you should check all pointers that may be invalid(for example a public function of your class that will be called by the user of the class may receive some invalid pointer but internal implementation may assume the pointer already checked).
首先,您应该检查所有可能无效的指针(例如,类的用户将调用的类的公共函数可能会收到一些无效的指针,但内部实现可能假定该指针已被检查)。
Second you should check result of functions that may fail, for example malloc
may fail to allocate memory or a file that you try to open may be deleted or you do not have permission to open it or even after opening it its data may be invalid, so you should check result of your action. This process in C++ is much easier than C, for example new
throw an exception on failure or stream
will be convertible to false
in case of any error or eof.
其次,您应该检查可能失败的函数的结果,例如malloc
可能无法分配内存或您尝试打开的文件可能被删除或您没有打开它的权限,甚至在打开它之后其数据可能无效,因此你应该检查你的行动的结果。C++ 中的这个过程比 C 容易得多,例如new
在失败时抛出异常或在出现任何错误或 eof 时stream
将转换为false
。
But to answer your question generally catch
block only catch typed exceptions but in some compilers catch(...)
may also catch exceptions like segmentation fault or even convert those exceptions to a C++ exception, for example under windows platform you may use _set_se_translator
to set a global translator for exceptions like that to C++ exceptions and with MSVC you can also compile your program with /EHa
to enable it catch those kind of exceptions in catch(...)
but all of this are extensions that are specific to specific platform or compiler thus write your code correctly and never think of such a way to solve your problem.
但是要回答您的问题,通常catch
只阻止捕获类型化的异常,但在某些编译器中catch(...)
也可能会捕获像分段错误这样的异常,甚至将这些异常转换为 C++ 异常,例如在 Windows 平台下,您可能会使用_set_se_translator
为这样的异常设置全局转换器C++ 异常和 MSVC,您还可以编译您的程序以/EHa
使其能够捕获这些异常,catch(...)
但所有这些都是特定于特定平台或编译器的扩展,因此正确编写您的代码,永远不要想出这样的方法来解决您的问题问题。
回答by Alexander Nekrasov
try to check is it catcheable with catch(...){cout<<'catched';}
尝试检查它是否可以捕获 catch(...){cout<<'catched';}
Also try this line, this way you prevent pushing wrong format points:
也试试这一行,这样你就可以防止推送错误的格式点:
if (!(ss >> a >> b)) {cout<<"wrong format"<<endl; continue;}
if (!(ss >> a >> b)) {cout<<"wrong format"<<endl; continue;}