1. 程式人生 > 其它 >C++ string_view 的坑(轉)

C++ string_view 的坑(轉)

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