您好,登錄后才能下訂單哦!
如何使用C++17 的 std::string_view避免字符串拷貝?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
C++中std::string是日常Coding中經(jīng)常使用的一個類,使用起來非常方便,但是也存在一些弊端。
如下代碼,參數(shù)傳遞的過程發(fā)生了內(nèi)存分配(Memory Allocation)和內(nèi)存拷貝。
void fun(const std::string& s) { std::cout << s << std::endl; } const char* ch = "hello world"; // bad way, expensive if the string is long fun(ch);
再看下面的常用的字符串截取實現(xiàn):
// very long string std::string str = "lllloooonnnngggg sssstttrrriiinnnggg"; // bad way, expensive if the string is long std::cout << str.substr(15, 10) << '\n';
為了進一步的壓榨程序的性能,需要移除掉這些昂貴的字符串內(nèi)存分配和拷貝操作。C++17中提供了std::string_view可以幫助我們實現(xiàn)這一功能,該類并不持有字符串的拷貝,而是與源字符串共享其內(nèi)存空間。
string_view構(gòu)造函數(shù)
constexpr basic_string_view() noexcept; (since C++17) constexpr basic_string_view(const basic_string_view& other) noexcept = default; (since C++17) constexpr basic_string_view(const CharT* s, size_type count);(since C++17) constexpr basic_string_view(const CharT* s); (since C++17) template<class It, class End>
雖然沒有定義參數(shù)為std::string的std::string_view函數(shù),下面的代碼仍然可以通過編譯。
std::string str("hello string view!"); std::string_view sview(str);
因為std::string類重載了std::string到std::string_view的轉(zhuǎn)換操作符。
operator basic_string_view<charT, traits>() const noexcept;
std::string_view避免內(nèi)存拷貝
有了string_view,我們就可以很好的解決文章開頭提到的問題。
void fun(const std::string_view& s) { std::cout << s << std::endl; } const char* ch = "hello world, char"; fun(ch); const std::string str = "hello world, string"; fun(str); fun({ch, 5});
有了std::string_view,函數(shù)參數(shù)不管是字符串?dāng)?shù)組指針,還是std::string,都不需要拷貝內(nèi)存源字符串。
// very long string std::string str = "lllloooonnnngggg sssstttrrriiinnnggg"; //Good way - No copies are created! std::string_view view = str; // string_view::substr returns a new string_view std::cout << view.substr(15, 10) << '\n';
同理,字符串的substr()函數(shù)也不需要再進行拷貝了,這對于非常長的字符串,可以有效的提升程序的性能表現(xiàn)。
std::string_view注意事項
由于std::string_view并不持有字符串的內(nèi)存,所以它的生命周期一定要比源字符串的生命周期長。一些典型的生命周期管理錯誤的例子:
std::string_view sv = std::string("hello world"); std::string_view fun() { std::string str("hello world"); return std::string_view(str); }
std::string_view的結(jié)尾并沒有\(zhòng)0結(jié)束符,所以在輸出std::string_view的時候要注意邊界,如下代碼:
#include <iostream> #include <vector> #include <string> #include <string_view> int main() { const char* ch = "hello world"; std::string_view sv(ch, 2); std::cout << sv << std::endl; std::cout << sv.data() << std::endl; return 0; }
程序輸出:
he hello world
std::cout << sv.data() << std::endl; 這行代碼輸出了hello world,這是因為sv仍然指向源字符串內(nèi)存,調(diào)用sv.data()打印時,仍然沿用了C++對于字符串的約定,直到遇到結(jié)束符\0時,打印才結(jié)束,這時候就輸出了完整的源字符串內(nèi)容。當(dāng)然這里明顯是不符合預(yù)期的,尤其是std::string_view指向的字符串沒有\(zhòng)0結(jié)束符的時候,程序很容易出現(xiàn)潛在的內(nèi)存問題。所以此處一定要小心。
看完上述內(nèi)容,你們掌握如何使用C++17 的 std::string_view避免字符串拷貝的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。