這個tip的背景是,將字串作為函式引數進行傳遞,
常規方法

將字串作為函式引數進行傳遞,容易想到的是以下兩個方法:
voidTakesCharStar(constchar* s);// C
voidTakesString(conststring& s);// Old Standard C++
這兩種方法只能接收確定型別的字串作為引數,否則可能需要型別轉換,比如下面這兩個場景:
一、使用c_str()函式將string型別顯式轉換為const char*:
voidAlreadyHasString(conststring& s){
TakesCharStar(s.c_str());// 顯式型別轉換
}
二、對于void TakesString(const string& s),即第二個方法,如果我們已有的資料是const char*型別,這時雖然不需要顯式地進行型別轉換,但是編譯器會執行拷貝操作來創建一個臨時的string
voidAlreadyHasCharStar(constchar* s){
TakesString(s);// compiler will make a copy
}
應該怎么辦?
谷歌建議利用string_view來傳遞字串引數,

需要注意的是,std::string_view到C++17標準才支持,否則的話你可以用absl::string_view
voidTakesStringView(absl::string_view s);// Abseil C++
voidTakesStringView(std::string_view s);// C++17 C++
string_view可以看成是一個字串快取的view,它只保留著這塊記憶體的地址和長度,也因此無法通過string_view來修改字串的內容,拷貝時也無需對實際的字串資料進行拷貝,
從const char*和const string&到string_view的型別轉換是隱式的,而且程序中也不會發生資料的拷貝,所以我們可以認為string_view的構造時間復雜度是O(1)的,
voidAlreadyHasString(conststring& s){
TakesStringView(s);// 沒有顯式的型別轉換
}
voidAlreadyHasCharStar(constchar* s){
TakesStringView(s);// 沒有拷貝
}
由于string_view不擁有實際的資料,而只是保存一個指向實際資料的指標,所以在使用string_view時我們需要保證:字串實際資料的生命周期要長于string_view,

如果你的API只在一次呼叫中需要使用這個字串,而且不需要修改其中的內容,此時使用string_view不需要有任何顧慮,如果后面還要使用這個字串,或者需要修改其中內容,可以使用string(my_string_view)進行顯式的型別轉換,

在現在的專案中使用string_view可能不會是一個明智的選擇,尤其是當一個字串在后續使用中確定需要string或者const char*型別,所以,如果想使用string_view,最好是在上游代碼中,或者是全新開始的新專案中,
注意
傳遞string_view可以大膽按值傳遞,因為其本身非常小
string_view不保證NUL-terminated,所以下面這種寫法不安全
printf("%s\n", sv.data());// DON’T DO THIS
但可以這樣用:
printf("%.*s\n",static_cast(sv.size()), sv.data());
std::cout<<"Took '"<< sv <<"'";
大多情況下,我們可以放心地把以const string&或const char*為引數的函式直接改寫為接收string_view型別,唯一的風險在于:如果在其他地方使用了函式的地址,則將導致Build中斷,因為生成的函式指標型別將不同,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/210730.html
標籤:其他
上一篇:第一個Django專案
