最近使用std::stringstream 格式化字符串,然後輸出打印。使用同一個std::stringsteram挨個序列化輸出,並調用str()輸出。每次輸出後都用clear()清除一下,但是結果沒想到的是居然會保存原來的內容。經過自己測試原來真的是這樣,測試代碼如下。
std::stringstream ss;
int temp = -1;
ss << "1 2 3";
std::cout << __LINE__ << " " << ss.str() << std::endl;
ss.clear();
ss << "4 5 6";
std::cout << __LINE__ << " " << ss.str() << std::endl;
以上代碼輸出爲
124 1 2 3
127 1 2 34 5 6
因此,經過百度,確實不能用這個clear()來清除內容;而應該使用str(""),該函數定義可以看到是將std::stringstream中的他部內容用傳入的字符串進行assgin,這樣便能清除內容。更正後如下
std::stringstream ss;
int temp = -1;
ss << "1 2 3";
std::cout << __LINE__ << " " << ss.str() << std::endl;
ss.str("");
ss << "4 5 6";
std::cout << __LINE__ << " " << ss.str() << std::endl;
結果爲:
124 1 2 3
127 4 5 6
這時我做了另外兩個測試,如果str("")中的參數不是空字符串呢;經過測試發現std::stringstream會將內容的內存和內容全部替換爲傳入的字符串,當你後面再使用<<時,依然從std::stringstream的起始位置開始覆蓋寫入,當內存不夠時再按<<所需補充;測試如下
std::stringstream ss;
int temp = -1;
ss << "1 2 3";
std::cout << __LINE__ << " " << ss.str() << std::endl;
ss.str("gggggwer");
ss << "4 5 6";
std::cout << __LINE__ << " " << ss.str() << std::endl;
結果爲:
124 1 2 3
127 4 5 6wer
我初始化多了wer時再使用<<,就會發現內容多出了wer;經過多次測試上面結論成立;
再使用少於於後面使用的字符串時就會被覆蓋
std::stringstream ss;
int temp = -1;
ss << "1 2 3";
std::cout << __LINE__ << " " << ss.str() << std::endl;
ss.str("ggg");
ss << "4 5 6";
std::cout << __LINE__ << " " << ss.str() << std::endl;
結果爲:
124 1 2 3
127 4 5 6
所以std::stringstream應該合理使用str(arg:str)來初始化內部內存與內容,當需要提前開闢空間時可以傳入一個固定長度的空字符串(傳入\0的字符串 未測試),如果想清空文本與內容那就str("")吧
那麼clear()怎麼用呢,這個求助百度後發現;是在使用>>將字符串轉成其它類型的時候用,用於清除內部的eof之類的文件標誌位
std::stringstream ss;
int temp = -1;
ss << "1";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
ss << "2";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
輸出結果:
125 1 1
128 1 1
如果是這樣呢
std::stringstream ss;
int temp = -1;
ss << "1 ";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
ss << "2";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
結果爲:
125 1 1
128 2 1 2
這次達標了,只是在1後面加了個空字符串;
爲它加上clear()之後
std::stringstream ss;
int temp = -1;
ss << "1";
ss >> temp;
ss.clear();
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
ss << "2";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
輸出爲:
126 1 1
129 2 12
可以看到當加入clear()後轉出的數據正常了,但是ss中的字符串內容已經變成12了,這個可以由上面的str("")來解釋;如果變成下面這樣
std::stringstream ss;
int temp = -1;
ss << "1";
ss >> temp;
ss.clear();
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
ss << "2";
ss << "34";
ss >> temp;
ss.clear();
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
ss << "56";
ss >> temp;
std::cout << __LINE__ << " " << temp << " " << ss.str() << std::endl;
輸出爲:
126 1 1
131 234 1234
134 56 123456
由此可見,每次使用>>轉出後,ss內部都會記錄一個已經轉到哪兒了的位置,然後下一次轉換就從這個位置開始到轉出類型結束位置或者換行或者空格的位置之間的內容轉出(可以百度std::stringstream >>結束分隔符)。
到此大概分晰完了,std::stringstream使用>>轉出時都會記錄轉出後的位置,如果是文件末尾了,你後面沒使用clear(),你使用<<已經不能再將內容追加到其後了,所以這是你爲啥後面的內容都是原來的值的原因。當使用clear()後,如果當前轉出記錄位置在文件末尾便會清除std::stringstream的eof標記(就是說已經轉到末尾了),使得後面你還可以追加內容,下一次又可以從該位置到下一個轉出類型的結束位置轉數據了。
一句話:當轉出數據已經轉到std::stringstream末尾了,使用clear(),繼續追加內容,繼續轉;就和一個剛開始的std::stringstream一樣;清除內容用str("");
需要注意的有這種情況
std::stringstream osstr("1 2 3");
std::vector<std::string> result;
std::copy(std::istream_iterator<std::string>(osstr), std::istream_iterator<std::string>(), std::back_inserter(result));
osstr.str("");
osstr.clear();
std::copy(result.begin(), result.end(), std::ostream_iterator<std::string>(osstr, ","));
這種情況osstr中的>>被隱藏到std::copy中去了,當這行代碼執行完時,轉出後位置已經在末尾了,要使用clear(),另外上面的想法是輸出轉化後的字符串,所以還有str("");