2016-07-20 8 views
2

古代の反パターンの1つは、エラーステータスをチェックし、「操作が失敗しました」の代わりに「操作が失敗しました」などのかなり役に立たないメッセージを返すことです。私はC++ファイルの入出力操作を例外で失敗させ、失敗した理由についてのエラーメッセージを取得します。具体的には、ファイルの作成が失敗したときにofstreamオブジェクトで例外が発生し、「許可が拒否されました」や「ファイルやパスがありません」などの便利なメッセージが表示されます。C++でファイルを作成するときIOエラーメッセージを取得するには?

これはC#やJava、Pythonなどの言語では簡単ですが、何らかの形でこのC++を実行する方法はありません。デフォルトでは、iostreamオブジェクトはただ静かに失敗します。いくつかのグローバルエラーコードがありますが、私はむしろ例外を持っています。検索の多くの後、私はあなたが次のコード行使用して例外を有効にすることをお読みください。)

my_file.exceptions(flog.exceptions() | std::ios::failbit | std::ifstream::badbit); 

動作しますが、今上げます例外がstd::ios_base::failureとex.what(ある「basic_iosのような無用の文字列を返します。 :クリア "。 std::ios_base::failureは、例外メッセージを出す.code()。message()を持つs​​ystem_errorから継承されると考えられていました。この奇妙さをここに控えておき、実際のエラーメッセージを返すべきではないことを決めた人に指先を指摘しないようにしましょう:)。問題は、C++ 11とG ++ 4.8.4でコンパイルしても、std::ios_base::failureがsystem_errorから実際に継承されていないことがわかります。

質問C++ 11モードでコンパイルする場合でもstd::ios_base::failureは4.8.4、最新のG ++でSYSTEM_ERRORから継承されていないのはなぜ

  1. ? GCCのC++ 11の実装はこの分野では不完全ですか、何かもっと何かをする必要がありますか?
  2. IO操作がC++で失敗し、エラーメッセージが表示されたときに、例外を発生させるという目標を達成するにはどうすればよいですか?最新のC++ 11やC++ 14でもこれを行う方法はありませんか?代替案は何ですか?

ここにサンプルコードがあります。あなたはcompile and run it hereです。

#include <iostream> 
#include <fstream> 
#include <system_error> 

int main() { 
    try { 
     std::ofstream flog; 
     flog.exceptions(flog.exceptions() | std::ios::failbit | std::ifstream::badbit); 
     flog.open("~/watever/xyz.tsv", std::ios::trunc); 
    } 
    catch (const std::ios_base::failure &ex) {  
     std::cout << "ios_base::failure: " << ex.what(); 
    } 
    catch(const std::system_error& ex) { 
     std::cout << "system_error: " << ex.code().message(); 
    } 
} 

答えて

3
  1. GCCのC++11 status documentationによると、 "システムエラーのサポートが" 完全にサポートされています。

    Bug 57953 - no C++11 compliant std::ios_base::failure foundによれば、ではstd::ios_base::failureが、system_errorからC++ 11に変更されました。更新されたios_base.hを見ると、std::ios_base::failureはが定義されている場合、system_errorから派生しています。その定義は、GCCのUsing Dual ABI文書に記載されています。

    Bug 66145 - [5/6/7 Regression] std::ios_base::failure objects thrown from libstdc++.so use old ABI

  2. が短い答えは:

    しかし、標準ライブラリのいくつかの作品が_GLIBCXX_USE_CXX11_ABIを定義しないという事実のために、まだ開いているstd::ios_base::failureとABIの問題に関する回帰がありますおそらく少なくともGCCの現在の実装では不可能でしょう。ライブラリ内のすべてを再コンパイルできない限り、_GLIBCXX_USE_CXX11_ABIが定義されていない限り。

+0

はhttp://en.cppreference.com/w/cpp/error/system_errorを見つけるためにGoogleしなければならなかったが、おかげで – strangeqargo

2

POSIXシステムでios失敗はので、あなたはそれを使用して意味のあるエラーメッセージを取得することができますerrnoを設定します。私は、多くの場合、次の操作を行います。

std::string getenv_as_string(std::string const& var) 
{ 
    auto ptr = std::getenv(var.c_str()); 
    return ptr ? ptr : ""; 
} 

// ~ doesn't work from C++ 
const std::string HOME = getenv_as_string("HOME"); 

int main() 
{ 
    try 
    { 
     std::ofstream ifs; 

     ifs.open(HOME + "/watever/xyz.tsv", std::ios::trunc); 

     if(!ifs) 
      throw std::runtime_error(std::strerror(errno)); 

     // Do stuff with ifs 
    } 
    catch(std::exception const& e) 
    { 
     std::cerr << e.what() << '\n'; 
    } 
} 

出力:

No such file or directory 
+0

はそれだろう代わりにios_base :: failure例外をスローし、fail()メソッドを使用する方が良いでしょう: 'if(flog.fail()) std :: ios_base :: failure(std :: strerror(errno)); – ShitalShah

関連する問題