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展示出來的數據, 這不是很矛盾嗎?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM