18

system_errorのライブラリでエラーを処理するために機能を使用しようとしています。役に立つと思われる場合に備えて、ライブラリの構造について簡単に説明します。ライブラリの名前空間 が呼び出されcommons、この下に という名前の別の名前空間がありますdynlibdynlib.so/.dll ファイルのロードを担当するクラスが含まれています。

namespace commons {
    namespace dynlib {
        class DynLibLoader {
        };
    }
}

DynLibLoader で発生する可能性があるエラーはLibraryFailedToLoadLibraryFailedToUnloadおよびSymbolNotFoundです。したがって、エラーを処理するための私の考えは次のとおりです。名前空間errorの下に名前空間を追加しますdynlib。次に、その名前空間の下で、 1 つの列挙型std::error_codesと 1つの列挙型を定義しますstd::error_conditions。私の理解では、 (Linux) または(Win32)std::error_codesの値に対応する必要があり、などの値に対応する必要があります。したがって、ここに私の質問があります。errnoGetLastErrorstd::error_conditionsLibraryFailedToLoadSymbolNotFound

  • 私の理解はstd::error_code正しいstd::error_conditionですか?
  • 列挙型の下でそれらを定義するために、可能なすべての値errnoを知るにはどうすればよいですか? 将来、Microsoft が API に追加のエラー値を追加した場合はどうなりますか? ソースコードに戻って、私が持っている列挙型の下でそれらを定義する必要がありますか?GetLastError()std::error_codesstd::error_codes
  • 別のプラットフォームを使用していて、エラーが発生したときに正確なシステム エラー コードを把握する方法がない場合はどうすればよいでしょうか?
  • std::error_codescommons 名前空間全体で同じものを使用し、 のstd::error_conditionようにサブ名前空間ごとに異なるものだけを定義したい場合はどうすればよいでしょうかdynlib。これは良い習慣ですか?これにより、コードの重複が回避されるため、はいと言います。しかし、これには裏があるのでしょうか。
  • 現時点ではstd::error_category、コモンズのサブ名前空間ごとに単一のものを使用しています。これは良い習慣ですか?を別の方法で使用する必要があると思いますstd::error_categoryか?
4

1 に答える 1

12

主な違いは、std::error_condition移植可能 (プラットフォームに依存しない) でstd::error_codeあるのに対し、プラットフォームに依存することです。通常、低レベルのプラットフォームに依存するコードが生成さerror_codesれ、クライアント コードはこれらerror_codesをプラットフォームに依存しないと比較しますerror_conditions

19.5 [syserr] は、(たとえば ) の特定の値に明示的に関連付けられている標準 (および移植可能な) エラー条件 (たとえば ) の長いリストを定義しerrc::no_such_file_or_directoryます。その結果、システムで生成される、または可能な値の完全なリストを知る必要はありません。コードに関連する標準値を知るだけで済みます。たとえば、ライブラリの実装は次のようになります。errnoENOENTerrnoGetLastError()

void MyLibraryClass::foo(std::error_code &ec)
{
    // whatever platform dependent operation that might set errno
    // possibly with alternative platform-dependent implementations
    ec = make_error_code(errno);
}

次に、クライアント コードは、 がerror_code特定の と一致するかどうかを確認しerror_conditionます。

error_code ec;
myLibraryInstance.foo(ec);
if (!ec)
{
    // success
}
else if (errc::no_such_file_or_directory == ec)
{
    // no_such_file_or_directory
}
else
{
    // unknown or unexpected error
}

あなたの場合、おそらく独自のエラーの列挙 (1 つの列挙のみ) を定義error_conditionsし、自動変換を有効にするようにタグ付けします。

namespace commons
{
namespace dynlib
{
    enum class errc {LibraryFailedToLoad=1, LibraryFailedToUnload, SymbolNotFound};
}
}
namespace std
{
    template<> struct is_error_condition_enum<commons::dynlib::errc> : true_type {};
}
// TODO: implement make_error_code and make_error_condition

error_condition次に、プラットフォームに依存するさまざまな操作の結果を適切な(または必要に応じて)変換できerror_codeます。

void DynLibLoader::open(std::error_code &ec)
{
    // possibly implement the windows version here as well
    if (NULL == dlopen(filename, flag))
    {
        ec = make_error_code(errc::LibraryFailedToLoad);
    }
}

クライアント コードは、上記のように、エラー コードを考えられるエラー条件と比較します。

error_code ec;
dynLibLoader.open(ec);
if (!ec)
{
    // success
}
else if (commons::dynlib::errc::LibraryFailedToLoad == ec)
{
    // Library Failed To Load
}
else
{
    // unknown or unexpected error
}

でタグ付けされているため、列挙型は(提供されたメソッドを使用して)commons::dynlib::errc::LibraryFailedToLoadに自動的に変換されることに注意してください。error_conditionmake_error_conditioncommons::dynlib::errcis_error_condition_enum

名前空間へのマッピングerror_categoryはおそらく個人的な好みですが、少し人工的です。この特定のケースでは、名前空間のカテゴリを持つことが理にかなっていることは事実ですが、dynlibいくつかの名前空間に広がるカテゴリを持つことが理にかなっている例を簡単に見つけることができます。場合によっては、すべての異なるエラー列挙型を一意の名前空間 (例: commons::errors) に配置することが意味があり、実用的である場合があります。

于 2015-01-10T00:26:50.127 に答える