在C++11中,因爲右值引用的引入,常爲人所詬病std::string的性能問題獲得了很大的改善。另一方面,咱們也能夠看到新語言爲std::string類增長了不少新的api。比較引人注意的就是std::string的成員函數stoi系列,以及std::to_string全局函數。這兩種API雖然很不起眼,卻爲C++11的格式化輸出(formatted I/O)增長了一種實用的手段。咱們能夠依序會議一下C,C++98,C++11中咱們是如何處理atoi/itoa的問題的:程序員
在C時代,一般咱們遇到atoi(字符串到數值轉換)的問題的時候咱們會使用<stdlib.h>中的atoi函數:編程
int num = atoi(cstr);api
這裏的cstr一般爲char或者const char類型的字符串。函數返回的結果則是該字符串所表示的一個十進制的integer。函數的整個效果則等同於<stdlib.h>中的另一個函數strtol:數組
int num = strtol(cstr, NULL, 10);安全
相比於atoi,strtol多了最後一個參數"radix"代表函數採用的是幾進制(這個進制數能夠從2到34,這個數值範圍的緣由顯而易見)。除去strtol會在出錯時設置全局的errno外,其效果與atoi系列中的atol則幾乎是徹底等同的。函數
而C時代解決itoa(數值到字符串的轉換)的時候,則採用了sprintf函數:性能
int myint; char buf[SIZE]; sprintf(buf, "my data is %d", myint);學習
這裏字符的輸出控制交給了"%d"這樣的特殊字符。經過特殊字符以及變長參數的配合(sprintf是變長參數函數),咱們得到預期的formatted I/O的輸出。 這裏咱們能夠看到C中對atoi/itoa的處理的特色,基本能夠概括以下:設計
到了C++98時代,atoi/itoa可使用新的C++標準庫來完成。具體地就是使用C++的流(stream)模板類。值得注意的是,在C++98代碼中,雖然字符串的存儲使用字符串數組也是徹底能夠的,但在C++代碼中使用std::string類型,內存能夠自行有效地管理,並且成員函數能夠拋出異常,因此更適用於C++代碼。而關於std::string類型的流模板類型就是std::stringstream。經過全局重載的operator <<以及operator >>,std::stringstream能夠很輕鬆地完成atoi或者是itoa的任務,好比:orm
ostringstream oss; oss << 15 << " is int, " << 3.14f << " is float." << endl; cout << oss.str();
oss就是一個字符串流對象,能夠用於itoa的工做。而
istringstream iss("12 14.1f"); int a; float b; iss >> a >> b; cout << a << " " << b << endl;
上面代碼中的iss字符串流對象,則可用做atoi。 從設計上講,std::stringstream算得上是一種好的設計。這是因爲使用std::stringstream的代碼看起來很是地直觀。並且因爲其來自於C++庫,程序員一般也不太關心是否會有exception拋出--由於若是代碼沒有try-catch block的話,exception一旦拋出,程序就會直接直接終止(調用std::terminate)。這種解決出錯的方式對於程序員來講更爲爽快,由於程序在問題點終止,就很容易找到出問題的代碼位置。而C時代的atoi/itoa,如同咱們講到的,須要程序員關注異常,若是漏過處理異常以後(其實這很常見),程序可能帶病運行。固然,因爲stringstream老是"附着"於一個內存能夠自行管理的string對象,因此程序員一般也沒必要擔憂任何的內存分配問題。 從設計角度出發看,std::stringstream幾乎無可挑剔。但在實際使用中,如咱們在上面提到的,不少人仍是願意使用C中的處理方法來完成atoi/itoa。這大概有兩方面的緣由:
到了C++11中,標準委員會多是注意到這種"簡單比完備"更重要的狀況,因而在C++11中,標準增長了全局函數std::to_string,以及std::stoi/stol/stoll等等函數。(最初的paper稱之爲simple numeric access,N1982)其用法很是簡單:
string s; s += to_string(12) + " is int, "; s += to_string(3.14f) + " is float."; cout << s << endl;
這裏的to_string會根據參數的類型完成相應類型地轉換。而:
string s("12"); int i = stoi(s); cout << i << endl;
這樣的代碼則能夠順利完成atoi的任務。因爲其是C++11引入的函數,因此具有C所不具有的全部的C++庫代碼特徵:根據類型的處理,拋出異常,以及自動內存管理。
能夠看到,std::to_string在實際使用中可能會涉及一些字符串的連結。如咱們在文章一開始提到的,C++98中字符串連結一直是C++語言被詬病性能低於C的一個重要方面。而這在C++11引入了右值引用後獲得了很大的緩解。所以此時std::to_string這樣的函數的實用性就大大加強了。不過std::to_string並非itoa的一種終極方式。以浮點數爲例,to_string甚至連浮點數小數位顯示控制這樣基本的控制功能都不具有,所以其最大地特色仍是突出在其易用性上。C++程序員沒必要定義一個std::stringstream對象就能夠完成安全有效且沒必要關心任何內存的itoa工做。 而std::stoi/stol/stoll...系列更是簡單到只能完成一個數值的轉換,比起老是返回std::stringstream &的operator >>比起來功能性就差很遠了。後者能在一行代碼中轉化出多個數值。但前者最大地特色仍然突出在易用性上,沒必要"附着"一個std::stringstream類型。這對不少無需複雜atoi的程序而言也就足夠了。