C++ string_view 的坑(轉)
阿新 • • 發佈:2021-06-30
C++17引入了string_view,這可是C++程式猿在處理字串操作的一大福音。因為string_view基本沒有涉及記憶體的額外分配。
但是在使用的時候,有個地方需要特別注意.我今天就踩到了這個坑,特此記錄一下.問題是這樣的,我寫了一個函式,入參是一個以一個點"."為分隔符的字串.函式的功能是把字串的字尾(也就是點後面的部分)替換掉生成一個新的字串.
程式碼如下:
1 string replace_post(string_view src, string_view new_post) 2 { 3 // 找到點的位置 4 auto pos = src.find(".") + 1; 5 // 取出點及點之前的全部字元,string_view的substr會返回一個 6 // string_view物件,所以要取data()賦值給string物件 7 string s1 = src.substr(0, pos).data(); 8 9 // 加上新的字尾 10 return s1 + new_post.data(); 11 } 12 13 14 int main() 15 { 16 string_view sv = "abcdefg.xxx"; 17 string s = replace_post(sv, "yyy"); 18 19 cout << sv << " replaced post by yyy result is:" << s << endl; 20 return 0; 21 }
這段程式碼導致我的程式出意料之外的bug,所以把它記錄在這裡.
原本希望的結果是abcdefg.yyy,而實際結果確是 abcdefg.xxxyyy
src.substr(0, pos).data() 得到的是原始的字串, 這與預期明顯不符啊. 難道string_view的substr方法有bug?剛開始我懷疑是編譯器的bug,於是我換不同的編譯器進行驗證。
用vc2019, gcc9.1, gcc9.3分別做了驗證, 結果都是一樣的.看來C++標準就是這麼定義的了. 那麼substr得到是什麼,c++文件裡說的一個string_view物件,這個物件裡到底有什麼資料?
1 string replace_post(string_view src, string_view new_post) 2 { 3 // 找到點的位置 4 auto pos = src.find(".") + 1; 5 // 取出點及點之前的全部字元,string_view的substr會返回一個string_view物件,所以要取data()賦值給string物件 6 string_view sv1 = src.substr(0, pos); 7 string s1 = sv1.data(); 8 cout << "sv1 = " << sv1 << ", s1=" << s1 << endl;9 10 // 加上新的字尾 11 return s1 + new_post.data(); 12 } 13 14 15 int main() 16 { 17 string_view sv = "abcdefg.xxx"; 18 string s = replace_post(sv, "yyy"); 19 20 cout << sv << " replaced post by yyy result is:" << s << endl; 21 return 0; 22 }
結果如下:
看來, sv1的輸出是正確的.但是sv1.data()得到確是整個原始字串,由此可以推斷string_view內部只是簡單地封裝原始字串的起始位置和結束位置,相當於給字串設定了一個觀察視窗,使用者只能看到通過視窗能看到的那部分資料. data()成員返回的是char*的指標,是string_view內部字串的起始位置.所以其表現再來的行為跟C字串一樣了,直到遇到空字串才結束.
總結,string_view只是某個字串上建立的一個檢視.它並不真正持有任何資料,展示給你的不一定是整個字串,可能只是其中一部分.
但要使用string_view看到的資料又只能通過data(),從上面例的結果來看: sv1.data()得到的結果卻不是sv1展示出來的資料,這不是很矛盾嗎?
https://www.cnblogs.com/pzhfei/p/12655601.html