20

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
4

6 に答える 6

15

try/catch は C++ 例外のみをキャッチします。セグメンテーション違反は、プログラムが不正なことを行い、未定義の動作を引き起こした場合にのみ発生します。

未定義の動作は、クラッシュしないなど、さまざまな形で現れる可能性があることに注意してください。プログラムがクラッシュして、修正が必要なことがあることを通知されるのは幸運ですが、プログラムがクラッシュしない場合もあります。フォールバック コードをクラッシュに依存させることはできません。

適切なことは、クラッシュを例外のように処理するのではなく、入力が期待どおりでない場合でも、プログラムが不正なことをしないようにすることです。この場合、ファイルが空で別のファイルを提供する必要があることを認識できるように、コードを変更する必要があります。


通常、セグメンテーション違反を処理する方法はありますが、探している種類の回復を行うことを意図したものではありません。仕組みは信号です。セグメンテーション違反の SIGSEGV など、指定したシグナルが発生したときに実行されるシグナル ハンドラをインストールできます。ただし、std::raise で明示的に発生させた場合を除き、そのようなシグナルが実際に発生する必要はありません。また、実装によってシグナルが発生したときにシグナルハンドラーで実行できることは、厳しく制限されています。

シグナルが、abort または raise 関数の呼び出しの結果以外で発生した場合、シグナル ハンドラーが、volatile sig_atomic_t として宣言されたオブジェクトに値を割り当てることによって、またはシグナルに値を代入することによって以外の静的ストレージ期間を持つオブジェクトを参照する場合、動作は未定義です。 handler は、標準ライブラリ内の任意の関数 (abort 関数、_Exit 関数、または最初の引数がハンドラの呼び出しの原因となったシグナルに対応するシグナル番号に等しいシグナル関数) 以外の関数を呼び出します。さらに、そのようなシグナル関数の呼び出しの結果として SIG_ERR が返された場合、errno の値は不確定です。

于 2012-10-19T17:56:26.733 に答える
8

プログラムにセグメンテーション違反があり、それが意図的に行ったものではない場合、それについてできることは何もありません。あなたはそれを捕まえることができません、そしてあなたがそれを捕まえることができたとしても、あなたはその後プログラムを続けることができません。

さらに、次のコードには非常に深刻な問題があります。

try {
    path=read_gesture("test.txt");
}
catch(int e) {
    path=read_gesture("test.txt");
}

「最初はうまくいかない場合は、もう一度やり直してください」は人間にとって良いモットーですが、コンピューターは毎回まったく同じように動作します。操作が失敗した場合、それが一時的な障害(ネットワーク障害など)でない限り、再試行は無駄です。

正しいプログラムはセグメンテーション違反を起こさないので、あなたの唯一の選択は正しいプログラムを書くことです。セグメンテーション違反を見つけたい場合は、ValgrindまたはGDBでプログラムを実行できます。どちらも、手がかりに満ちたバックトレースを提供するはずです(ただし、プログラムの真のエラーを見つけるには、頭を使う必要があります)。

もう1つの方法は、Java、C#、Python、Ruby、Haskell、JavaScript、Go、Rust、またはCやC ++を除く最近使用されているほとんどすべての言語など、segfaultを取得しない言語を使用することです。

脚注:セグメンテーション違反を取得する正しいプログラムを実際に作成することは可能であるため、これは少し単純化されています。しかし、それはあなたがしていることではありません。

于 2012-10-19T16:18:29.533 に答える
2

少しテストを追加して、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グローバル関数を参照してください。失敗した場合は、ここでチェックされていないビットが設定されます。

エラーは、内部状態フラグを変更することによって通知されます。

  • eofbit:操作中に文字のソースの終わりに到達します。
  • failbit:終わりが時期尚早に見つかったため、文字は抽出されませんでした。一部のeofbitケースでもfailbitが設定されることに注意してください。
  • badbit:上記以外のエラーが発生しました。

さらに、これらのいずれの場合でも、isのメンバー関数ios :: exceptionsで適切なフラグが設定されていると、タイプios_base::failureの例外がスローされます。

于 2012-10-19T16:19:04.770 に答える
1

まず第一に、セグメンテーション違反などの例外を決して生成しないようにコードを書くことができます (読むべきです)。

最初に、無効である可能性のあるすべてのポインターを確認する必要があります (たとえば、クラスのユーザーによって呼び出されるクラスのパブリック関数は、無効なポインターを受け取る場合がありますが、内部実装では、ポインターが既にチェックされていると見なされる場合があります)。

次に、失敗する可能性のある関数の結果を確認する必要があります。たとえば、mallocメモリの割り当てに失敗したり、開こうとしたファイルが削除されたり、開く権限がないか、開いた後でもデータが無効になる可能性があります。アクションの結果を確認する必要があります。C++ でのこのプロセスは、C よりもはるかに簡単です。たとえばnew、失敗時に例外をスローしたり、エラーまたは eof の場合にstream変換可能になります。false

しかし、あなたの質問に答えるには、通常、catchタイプされた例外のみをブロックしますが、一部のコンパイラでcatch(...)は、セグメンテーション違反などの例外をキャッチしたり、それらの例外を C++ 例外に変換したりすることもあります_set_se_translator。 C++ 例外と MSVC を使用して、プログラムをコンパイルして、/EHaそのような例外をキャッチできるようにすることもできますcatch(...)が、これらはすべて、特定のプラットフォームまたはコンパイラに固有の拡張機能であるため、コードを正しく記述し、問題を解決するそのような方法を決して考えないでください。問題。

于 2012-10-19T16:40:49.927 に答える
-1

それがキャッチ可能かどうかを確認してみてくださいcatch(...){cout<<'catched';}

また、この行を試してください。これにより、間違ったフォーマットポイントをプッシュするのを防ぐことができます。

if (!(ss >> a >> b)) {cout<<"wrong format"<<endl; continue;}

于 2012-10-19T16:19:29.257 に答える