首先说明invalid_argument是一个类(class invalid_argument;),它的继承关系如下
exception-------->logic_error--------->invalid_argument
invalid_argument原型是
1class invalid_argument:public logic_error {2public:3explicit invalid_argument (conststring& 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 }2021return0;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,constint& a,constint& h) 9 :name(n),age(a),height(h)10 {}1112 inline voidset(const std::string& n,constint& a,constint& 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 }2223 inline bool valid(const std::string& n, constint& a, constint& 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;3132};3334int main(int argc, char** argv)35{36 People p("Li San", 20 , 170);37try38 {39 p.set("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(constchar * f, constchar * l, constchar * fun) 38 :file(f), line(l), func(fun) 39 {} 40 41 inline std::string getFile() const 42 { 43returnthis->file; 44 } 45 46 inline std::string getLine() const 47 { 48returnthis->line; 49 } 50 51 inline std::string getFunc() const 52 { 53returnthis->func; 54 } 55private: 56constchar* file; 57constchar* line; 58constchar* func; 59}; 60 61 std::stringoperator +(const std::string & str, const ErrorInfo& ei) 62{ 63 std::string strTemp(ei.getFile() + ":" + ei.getLine() + ":" + ei.getFunc()); 64 strTemp +=str; 65return strTemp; 66//return str::string(ei.getFile() + ":" + 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,constint& a,constint& h) 83 :name(n),age(a),height(h) 84 {} 85 86 inline voidset(const std::string& n,constint& a,constint& 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 } 99100 inline bool valid(const std::string& n, constint& a, constint& 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;108109};110111int main(int argc, char** argv)112{113 People p("Li San", 20 , 170);114try115 {116 p.set("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::set(const std::string&, constint&, constint&)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) #x5#define TOSTRING(x) TTOSTRING(x)6...7...8//后面代码与上面一样
其运行结果为:
TestError: invalid_a.cpp:91:void People::set(const std::string&, constint&, constint&)Invalid People
至于里面原理,为什么两次就能够将__LINE__表示的数字例如(71)转换成const char* “71”,而不是转换成“__LINE__"const char*字符串,希望清楚的园友,给出答案,谢谢!