c++ namespace - كيفية الحصول على رسالة خطأ عندما يفشل ifstream مفتوحة




using std (5)

يمكنك محاولة ترك البث يعرض استثناء عن الفشل:

std::ifstream f;
//prepare f to throw if failbit gets set
std::ios_base::iostate exceptionMask = f.exceptions() | std::ios::failbit;
f.exceptions(exceptionMask);

try {
  f.open(fileName);
}
catch (std::ios_base::failure& e) {
  std::cerr << e.what() << '\n';
}

e.what() ، ومع ذلك ، لا يبدو أن تكون مفيدة للغاية:

  • لقد حاولت ذلك على Win7 ، Embarcadero RAD Studio 2010 حيث يعطي "ios_base :: مجموعة failbit" في حين strerror(errno) "لا يوجد ملف أو دليل."
  • على Ubuntu 13.04 ، يقول gcc 4.7.3 الاستثناء "basic_ios :: clear" (بفضل arne )

إذا لم يعمل e.what() نيابة عنك (لا أعرف ما e.what() عن الخطأ ، نظرًا لأن ذلك غير قياسي) ، حاول استخدام std::make_error_condition (C ++ 11 فقط):

catch (std::ios_base::failure& e) {
  if ( e.code() == std::make_error_condition(std::io_errc::stream) )
    std::cerr << "Stream error!\n"; 
  else
    std::cerr << "Unknown failure opening file.\n";
}
ifstream f;
f.open(fileName);

if ( f.fail() )
{
    // I need error message here, like "File not found" etc. -
    // the reason of the failure
}

كيفية الحصول على رسالة خطأ كسلسلة؟


كل مكالمة نظام تفشل في تحديث قيمة errno .

وبالتالي ، يمكنك الحصول على مزيد من المعلومات حول ما يحدث عند فشل فتح ifstream باستخدام شيء مثل:

cerr << "Error: " << strerror(errno);

ومع ذلك ، بما أن كل استدعاء نظام يقوم بتحديث قيمة errno العالمية ، فقد يكون لديك مشكلات في تطبيق ذو مؤشرات ترابط متعددة ، في حالة تشغيل استدعاء نظام آخر لخطأ بين تنفيذ f.open واستخدام errno .

على النظام مع معيار POSIX:

errno هو مؤشر الترابط المحلية؛ وضعه في موضوع واحد لا يؤثر على قيمته في أي موضوع آخر.

تحرير (بفضل Arne Mertz وغيره من الأشخاص في التعليقات):

e.what() بدا في البداية أن يكون أكثر C ++ - الطريقة الصحيحة أصلا لتنفيذ ذلك ، ومع ذلك ، فإن السلسلة التي يتم إرجاعها بواسطة هذه الوظيفة تعتمد على التنفيذ و (على الأقل في + l + libstdc ++) هذه السلسلة لا تحتوي على معلومات مفيدة حول السبب وراء الخطأ...


بعد الإجابة علىArne Mertz ، اعتبارًا من C ++ 11 std::ios_base::failure من system_error (راجع http://www.cplusplus.com/reference/ios/ios_base/failure/ ) ، والذي يحتوي على كل من الخطأ رمز والرسالة التي strerror(errno) .

std::ifstream f;

// Set exceptions to be thrown on failure
f.exceptions(std::ifstream::failbit | std::ifstream::badbit);

try {
    f.open(fileName);
} catch (std::system_error& e) {
    std::cerr << e.code().message() << std::endl;
}

هذا يطبع No such file or directory. إذا لم يكن fileName موجودًا.


يمكنك أيضًا رمي std::system_error كما هو موضح في كود الاختبار أدناه. يبدو أن هذه الطريقة تنتج مخرجات أكثر قابلية للقراءة من f.exception(...) .

#include <exception> // <-- requires this
#include <fstream>
#include <iostream>

void process(const std::string& fileName) {
    std::ifstream f;
    f.open(fileName);

    // after open, check f and throw std::system_error with the errno
    if (!f)
        throw std::system_error(errno, std::system_category(), "failed to open "+fileName);

    std::clog << "opened " << fileName << std::endl;
}

int main(int argc, char* argv[]) {
    try {
        process(argv[1]);
    } catch (const std::system_error& e) {
        std::clog << e.what() << " (" << e.code() << ")" << std::endl;
    }
    return 0;
}

مخرجات المثال (Ubuntu w / clang):

$ ./test /root/.profile
failed to open /root/.profile: Permission denied (system:13)
$ ./test missing.txt
failed to open missing.txt: No such file or directory (system:2)
$ ./test ./test
opened ./test
$ ./test $(printf '%0999x')
failed to open 000...000: File name too long (system:36)

لا ، ولكن يمكن أن يكون لها مرجع أو مؤشر لنفسها:

class Node
{
    Node *pnode;
    Node &rnode;
};




c++ error-handling stream std