std::invalid_argument应⽤
⾸先说明invalid_argument是⼀个类(class invalid_argument;),它的继承关系如下
exception-------->logic_error--------->invalid_argument
invalid_argument原型是
1class invalid_argument:public logic_error {
2public:
3explicit invalid_argument (const string& what_arg);
4 };
它在stdexcept头⽂件中,在std命名空间内。下⾯举⼀个例⼦来使⽤它
1 #include <iostream>
2 #include <stdexcept>
3
4int main(int argc,char ** argv)
5 {
6try
7 {
8bool errorArgument;
9 errorArgument=true;
10if(errorArgument)
11 {
12throw std::invalid_argument("occur error!");
13 }
14 }
15catch(std::invalid_argument &ia)
16 {
17//what()为invalid_argument继承exception类的函数
18 std::cerr<<" Invalid_argument "<< ia.what()<<std::endl;
19 }
20
21return0;
22 }
运⾏结果为:
Invalid_argument occur error!
那么上⾯的例⼦是⼀个最简单的应⽤了。invalid_argument顾名思义指⽆效参数,这个应该应⽤在检查参数是否是⽆效的,⼀般检查参数⽤于特定的函数以及类,那么就应该是给类的成员变量赋值或者函数参数赋值时,检查其赋给它们的值是否有效,例如有⼀个类(people,有三个成员变量name,age,height)那么我们知道⼈的年龄在0~150岁之间(ps:如果对于程序员可以直接定义为0~75)。⾝⾼的话
0~300cm,名字的长度不会超过20。如果都超过这些范围,就可以认定是⽆效数据。那么这个类可以如下定义:
1 #include <stdexcept>
2 #include <iostream>
3 #include <string>
4
5class People
6 {
7public:
8 People(const std::string& n,const int& a,const int& h)
9 :name(n),age(a),height(h)
10 {}
11
12 inline void t(const std::string& n,const int& a,const int& h)
13 {
14if(!valid(n,a,h))
15 {
16throw std::invalid_argument("People's argument is error");
17 }
18 name = n;
19 age = a;
20 height = h;
21 }
22
23 inline bool valid(const std::string& n, const int& a, const int& h)
24 {
25return ( n.length() == 0 ||n.length() > 20 )&& a >= 0 && a< 150 && h > 0 && h < 300 ;
26 }
27private:
28 std::string name;
29int age;
30int height;
31
32 };
33
34int main(int argc, char** argv)
35 {
36 People p("Li San", 20 , 170);
37try
38 {
39 p.t("Li San" , 20 ,1700);
40 }
41catch (std::invalid_argument & ia)
42 {
43 std::cerr << "Error: " << ia.what() << std::endl;
44 }
45return0;
46 }
其运⾏结果为:
Error: People's argument is error
上⾯程序只要输⼊⽆效数据,就会输出错误。但是仅仅这样是不够的,我们还⽆法定位⽆效参数在哪个⽂件与哪个⼀⾏或者在哪个函数中,如果在打印错误的时候连这些信息⼀并输出相信定位问题就⽅便多了。那么我们在报出错误信息的时候连这些信息也附加上就明确多了。
1 #include <stdexcept>
2 #include <iostream>
3 #include <string>
4#define TOSTRING(x) #x
5
6//class ErrorInfo
7//{
8// public:
9// ErrorInfo(const std::string& f,const std::string& l,const std::string& fun)
10// : file(f), line(l), func(fun)
11// {}
12//
13// inline const std::string getFile() const
14// {
15// return this->file;
16// }
17//
18// inline const std::string getLine() const
19// {
20// return this->line;
21// }
22//
23// inline const std::string getFunc() const
24// {
25// return this->func;
26// }
27//
28// private:
29// const std::string file;
30// const std::string line;
31// const std::string func;
32//};
33
34class ErrorInfo
35 {
36public:
37 ErrorInfo(const char * f, const char * l, const char * fun)
38 :file(f), line(l), func(fun)
39 {}
40
41 inline std::string getFile() const
42 {
43return this->file;
44 }
45
46 inline std::string getLine() const
47 {
48return this->line;
49 }
50
51 inline std::string getFunc() const
52 {
53return this->func;
54 }
55private:
56const char* file;
57const char* line;
58const char* func;
59 };
60
61 std::string operator +(const std::string & str, const ErrorInfo& ei)
62 {
63 std::string File() + ":" + ei.getLine() + ":" + ei.getFunc());
64 strTemp +=str;
65return strTemp;
66//return str::File() + ":" + ei.getLine() + ":" + ei.getFunc() += str );
67 }
68
69class InvalidPeople:public std::invalid_argument
70 {
71public:
72 InvalidPeople(ErrorInfo & ei)
73 : std::invalid_argument( "Invalid People " + ei )
74 {}
75 ~InvalidPeople() throw()
76 {}
77 };
78
79class People
80 {
81public:
82 People(const std::string& n,const int& a,const int& h)
83 :name(n),age(a),height(h)
84 {}
85
86 inline void t(const std::string& n,const int& a,const int& h)
87 {
88if(!valid(n,a,h))
89 {
90 ErrorInfo ei(__FILE__,TOSTRING(__LINE__),__PRETTY_FUNCTION__);
91// ErrorInfo ei(__FILE__,#__LINE__,__PRETTY_FUNCTION__);
92throw InvalidPeople(ei);
93// throw InvalidPeople(ErrorInfo(__FILE__,TOSTRING(__LINE__),__PRETTY_FUNCTION__));
94 }
95 name = n;
96 age = a;
97 height = h;
98 }
99
100 inline bool valid(const std::string& n, const int& a, const int& h)
101 {
102return ( n.length() == 0 ||n.length() > 20 )&& a >= 0 && a< 150 && h > 0 && h < 300 ;
103 }
104private:
105 std::string name;
106int age;
107int height;
108
109 };
110
111int main(int argc, char** argv)
112 {
113 People p("Li San", 20 , 170);
114try
115 {
116 p.t("Li San" , 20 ,1700);
117 }
118catch (std::invalid_argument & ia)
119 {
120 std::cerr << "Error: " << ia.what() << std::endl;
121 }
122return0;
123 }
其运⾏结果为:
TestError: invalid_a.cpp:__LINE__:void People::t(const std::string&, const int&, const int&)Invalid People
注意:
(1)上⾯#define TOSTRING(x) #x就可以将int类型转换为const char *类型。
(2) __FILE__是const char*类型,并且通过#define TOSTRING(x)转换后的类型为const char*类型,编译器是gun那么获取所在的函数名称就是__PRETTY_FUNCTION__也是const char*类型。
可以看到__LINE__并没有显⽰出⾏号,这⾥原因编译器直接将__LINE__其转换为"__LINE__"这个字符串了那么这⾥如何解决呢?笔者试过好多⽅法,最终找出来了,我们可以在#define⼀次,就可以正常现实了。如下代码
1 #include <stdexcept>
2 #include <iostream>
3 #include <string>
4#define TTOSTRING(x) #x
5#define TOSTRING(x) TTOSTRING(x)
6 ...
7 ...
8//后⾯代码与上⾯⼀样
其运⾏结果为:
TestError: invalid_a.cpp:91:void People::t(const std::string&, const int&, const int&)Invalid People
⾄于⾥⾯原理,为什么两次就能够将__LINE__表⽰的数字例如(71)转换成const char* “71”,⽽不是转换成“__LINE__"const char*字符串,希望清楚的园友,给出答案,谢谢!