首先說明invalid_argument是一個類(class invalid_argument;),它的繼承關系如下
exception-------->logic_error--------->invalid_argument
invalid_argument原型是
1 class invalid_argument:public logic_error { 2 public: 3 explicit invalid_argument (const string& what_arg); 4 };
它在stdexcept頭文件中,在std命名空間內。下面舉一個例子來使用它
1 #include <iostream> 2 #include <stdexcept> 3 4 int main(int argc,char ** argv) 5 { 6 try 7 { 8 bool errorArgument; 9 errorArgument=true; 10 if(errorArgument) 11 { 12 throw std::invalid_argument("occur error!"); 13 } 14 } 15 catch(std::invalid_argument &ia) 16 { 17 //what()為invalid_argument繼承exception類的函數 18 std::cerr<<" Invalid_argument "<< ia.what()<<std::endl; 19 } 20 21 return 0; 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 5 class People 6 { 7 public: 8 People(const std::string& n,const int& a,const int& h) 9 :name(n),age(a),height(h) 10 {} 11 12 inline void set(const std::string& n,const int& a,const int& h) 13 { 14 if(!valid(n,a,h)) 15 { 16 throw 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 { 25 return ( n.length() == 0 ||n.length() > 20 )&& a >= 0 && a< 150 && h > 0 && h < 300 ; 26 } 27 private: 28 std::string name; 29 int age; 30 int height; 31 32 }; 33 34 int main(int argc, char** argv) 35 { 36 People p("Li San", 20 , 170); 37 try 38 { 39 p.set("Li San" , 20 ,1700); 40 } 41 catch (std::invalid_argument & ia) 42 { 43 std::cerr << "Error: " << ia.what() << std::endl; 44 } 45 return 0; 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 34 class ErrorInfo 35 { 36 public: 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 { 43 return this->file; 44 } 45 46 inline std::string getLine() const 47 { 48 return this->line; 49 } 50 51 inline std::string getFunc() const 52 { 53 return this->func; 54 } 55 private: 56 const char* file; 57 const char* line; 58 const char* func; 59 }; 60 61 std::string operator +(const std::string & str, const ErrorInfo& ei) 62 { 63 std::string strTemp(ei.getFile() + ":" + ei.getLine() + ":" + ei.getFunc()); 64 strTemp +=str; 65 return strTemp; 66 //return str::string(ei.getFile() + ":" + ei.getLine() + ":" + ei.getFunc() += str ); 67 } 68 69 class InvalidPeople:public std::invalid_argument 70 { 71 public: 72 InvalidPeople(ErrorInfo & ei) 73 : std::invalid_argument( "Invalid People " + ei ) 74 {} 75 ~InvalidPeople() throw() 76 {} 77 }; 78 79 class People 80 { 81 public: 82 People(const std::string& n,const int& a,const int& h) 83 :name(n),age(a),height(h) 84 {} 85 86 inline void set(const std::string& n,const int& a,const int& h) 87 { 88 if(!valid(n,a,h)) 89 { 90 ErrorInfo ei(__FILE__,TOSTRING(__LINE__),__PRETTY_FUNCTION__); 91 // ErrorInfo ei(__FILE__,#__LINE__,__PRETTY_FUNCTION__); 92 throw 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 { 102 return ( n.length() == 0 ||n.length() > 20 )&& a >= 0 && a< 150 && h > 0 && h < 300 ; 103 } 104 private: 105 std::string name; 106 int age; 107 int height; 108 109 }; 110 111 int main(int argc, char** argv) 112 { 113 People p("Li San", 20 , 170); 114 try 115 { 116 p.set("Li San" , 20 ,1700); 117 } 118 catch (std::invalid_argument & ia) 119 { 120 std::cerr << "Error: " << ia.what() << std::endl; 121 } 122 return 0; 123 }
其運行結果為:
TestError: invalid_a.cpp:__LINE__:void People::set(const std::string&, const int&, const int&)Invalid People
可以看到__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::set(const std::string&, const int&, const int&)Invalid People
至於里面原理,為什么兩次就能夠將__LINE__表示的數字例如(71)轉換成const char* “71”,而不是轉換成“__LINE__"const char*字符串,希望清楚的園友,給出答案,謝謝!
