0%

Introduction to std::error_code

前陣子沉迷於大唐雙龍傳,所以耍廢了一陣子,來紀錄一下新學到的觀念

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_NOTFOUNDLibB_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());
}

} // end namespace errc
} // end namespace mylib

namespace std {

template<>
struct is_error_code_enum<mylib::errc::my_error>
: std::true_type
{ };

} // end namespace std

int main()
{
std::error_code ec1 = mylib::errc::make_error_code(mylib::errc::failed); // works
std::error_code ec2 = mylib::errc::failed; // works
bool result = (ec2 == mylib::errc::failed); // works

std::cout << ec1 << std::endl;
}