16

現在、 libjpegを使用して JPEG 画像を保存しています。エラーが発生した場合、libjpeg のデフォルトの動作は を呼び出すexit()ことですが、これは私のプログラムにとって致命的なエラーではないため、回避したいと考えています。libjpegでは、独自のエラー マネージャーを使用できますerror_exit()。また、独自の関数 (exit()既定で呼び出す)を使用する場合は、制御を呼び出し元に返してはならないことが義務付けられています。libjpeg は、プログラムではなくsetjmp.hを使用してこの要件を満たすことを提案してexit()います。

ただし、私は C++ プログラムを作成しており、例外にアクセスできます。この質問の答えは、(明確に定義された動作のように) コールバックから例外をスローしても安全であると述べています。ただし、動的ライブラリについては言及されておらず、動的ライブラリの境界を越えて例外をスローしないという一般的な経験則があります。

次に例を示します。

#include <iostream>
#include <jpeglib.h>
#include <cstdio>
#include <stdexcept>

static void handleLibJpegFatalError(j_common_ptr cinfo)
{
  (*cinfo->err->output_message)(cinfo);
  throw std::runtime_error("error in libjpeg, check stderr");
}

int main()
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example

  try
    {
      cinfo.err = jpeg_std_error(&jerr);
      jerr.error_exit = handleLibJpegFatalError;

      // let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called
      // by libjpeg
      jpeg_create_compress(&cinfo);
    }
  catch (...)
    {
      std::cerr << "Error saving the JPEG!\n";
    }

  jpeg_destroy_compress(&cinfo);
  std::fclose(file);
}

私が知りたいのは、libjpeg が動的ライブラリとしてコンパイルされている場合でも、このコールバックから例外をスローし、それをアプリケーションでキャッチすることはできますか? libjpeg は静的ライブラリまたは動的ライブラリである可能性があり、動的ライブラリの場合は別のコンパイラでビルドされている可能性があります。ただし、例外をスローしてキャッチするコードは、確実に同じコンパイル単位にあります。上記のコードは安全ですか?

参考までに、私は OS X と Windows 向けに開発しています (そして、将来の Linux の可能性を念頭に置いています) ので、これが特定のプラットフォームではなく、一般的に明確に定義された動作であることが知られているかどうかにもっと興味があります/コンパイラ。

4

3 に答える 3

6

他の答えはここに当てはまります。スタックを巻き戻すときに、何も破棄されません。C++実装の例外処理構造(Cプログラムとしてはそうではない)を特に混乱させない限り、ライブラリが内部でクレイジーな呼び出し規約を使用していても問題ありません。私が知っている C++ の実装では、スタック フレームをポップして catch ブロックを見つけることはできません (これは最適化を悪夢にします)。それらはすべて、例外処理のために内部構造を維持します。呼び出しチェーンの下位にある呼び出しがこれらの構造を台無しにしない限り、スタックの巻き戻しはすべての個人的なコードに対して完全に正常に機能します。さて、一般に、クリーンアップのためにライブラリに実行を返さないため、ライブラリの内部状態がめちゃくちゃになる可能性は十分にあります。

この場合、私はそれに行きます。一般に、C コールバックからは致命的な例外のみをスローします。

それが役に立ったことを願っています。

于 2012-06-08T22:42:14.757 に答える
5

安全ではありません。関連する非 C++ ライブラリ コードのコンパイル方法によっては、必要なアンワインド テーブルが存在しない場合があります。これは、失敗する可能性がある実際的な理由にすぎません。概念的な理由は、単に未定義の動作だからです。

ドキュメントに従い、setjmp/longjmpを使用して libjpeg コードへの呼び出しのすぐ外に出てから、例外if (setjmp(...)) { ... }を使用する場合は本体ですぐに例外をスローする必要があります。

于 2012-06-08T23:06:10.970 に答える