前陣子沉迷於大唐雙龍傳,所以耍廢了一陣子,來紀錄一下新學到的觀念
How to deal error in C language
簡單直接的作法,定義error,然後把ReturnCode當作ErrorCode回傳
1 2 3 4 5 6 7 8 9 10 11
| enum errors { SUCCESS = 0, NOTFOUND, }; int openFile(const char *filename, int *pfd) { int fd = open(filename, , O_RDONLY); if (fd == -1) return NOTFOUND; *pfd = fd; return SUCCESS; }
|
不過這邊有個小問題,當兩個不同的Componet有相同的ErrorCode怎麼辦,假設LibA和LibB都有NOTFOUND的定義
通常的作法就是改名,然後用類似LibA_NOTFOUND
和LibB_NOTFOUND
來繞過
How to deal error in pre C++11
當然是用Exception來表示Error
1 2 3 4 5 6
| int openFile(const char *filename) { int fd = open(filename, , O_RDONLY); if (fd == -1) throw std::exception("File not fould"); return fd; }
|
遮方式當然也有缺點,需要考慮Runtime overhead,有些Coding Style不鼓勵用Exception(例如Google)
std::error_code in C++11
C++11從Boost引進了error_code的觀念
1 2 3 4 5 6 7 8 9 10 11 12 13
| int openFile(const char *filename, std::error_code &ec) { int fd = open(filename, , O_RDONLY); if (fd == -1) ec = std::error_code(errno, std::system_category()); return fd; } std::error_code ec; int fd = openFile(filePath, ec); if (ec) { std::cout << "Category: " << ec.category().name() << "Value: " << ec.value() << '\n' << "Message: " << ec.message() << '\n'; }
|
這邊作法類似於C語言的作法,不過不同的是引進了Category的觀念
於是可以自定義一個Category和自己的Error_code,解決了Conflict的問題
不過如果需要的話,當然也可以當Exception丟出去
1 2
| int fd = openFile(filePath, ec); if (ec) throw ec;
|
當你需要時才把Exception丟出
std::error_condtion
如果要對Error做條件處理該怎麼做,野引進了error_condtion的觀念
1 2 3 4 5 6 7 8 9
| int fd = openFile(filePath, ec); std::error_condition cond1(1, std::system_category()); std::error_condition cond2(2, std::system_category()); if (ec == cond1) { } else if (ec == cond2) { } else { }
|
Custom your categlory and error_code
從Stackoverflow看到如何自定義ErrorCode和Category的方式,記錄下來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include <iostream> using namespace std; #include <system_error> #include <cassert>
namespace mylib { namespace errc {
enum my_error { failed = 0 };
inline const char* error_message(int c) { static const char* err_msg[] = { "Failed", };
assert(c < sizeof(err_msg) / sizeof(err_msg[0])); return err_msg[c]; }
class my_error_category : public std::error_category { public:
my_error_category() { }
std::string message(int c) const { return error_message(c); }
const char* name() const noexcept { return "My Error Category"; }
const static error_category& get() { const static my_error_category category_const; return category_const; } };
inline std::error_code make_error_code(my_error e) { return std::error_code(static_cast<int>(e), my_error_category::get()); }
} }
namespace std {
template<> struct is_error_code_enum<mylib::errc::my_error> : std::true_type { };
}
int main() { std::error_code ec1 = mylib::errc::make_error_code(mylib::errc::failed); std::error_code ec2 = mylib::errc::failed; bool result = (ec2 == mylib::errc::failed);
std::cout << ec1 << std::endl; }
|