可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Does a try-catch
block catch segmentation fault errors?
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 of try
, that was a typo.
回答1:
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.
回答2:
try/catch only catches C++ exceptions. Segmentation faults will only occur when your program does something illegal and invokes undefined behavior.
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;
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.
回答3:
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).
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++.
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.
回答4:
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.
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.
回答5:
You can try to add a little test to see if ifs is valid:
#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();
See the getline global function for more information, if it fail, it set some bit not checked here.
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.
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.
回答6:
try to check is it catcheable with catch(...){cout<<'catched';}
Also try this line, this way you prevent pushing wrong format points:
if (!(ss >> a >> b)) {cout<<"wrong format"<<endl; continue;}