Google C++毎週贴士#1:string_view
(原文リンク:https://abseil.io/tips/1翻訳者:[email protected])
毎週贴士#1:string_viewは2012-04-20 に最初に発表された.著者:Michael Chastain(mec.)[email protected]) は2017-09-18 に更新されました.
string_とはview、そしてどうしてあなたは関心を持つべきですか?
関数受け入れ(定数)文字列を入力パラメータとして書く必要がある場合は、4つのオプションがあります.そのうち2つはすでに知っていますが、他の2つはまだ知らないかもしれません.
関数呼び出し時にすでに対応するフォーマットの文字列が存在し、前の2つの方法が最適である.しかし、タイプ変換が必要な場合はどうすればいいですか(
Callers needing to convert a const char* to a string don’t need to do anything additional (the good news) but will invoke the creation of a (convenient but inefficient) temporary string, copying the contents of that string (the bad news):
どうやって解決しますか?
Googleは、
APIが単一の関数呼び出しで文字列データを使用し、その文字列データを変更する必要がない場合は、
既存のコード・ライブラリに
追加の説明は他の文字列タイプとは異なり、 . を直接印刷できます.ほとんどの場合、既存の関数の
毎週贴士#1:string_view
string_とはview、そしてどうしてあなたは関心を持つべきですか?
関数受け入れ(定数)文字列を入力パラメータとして書く必要がある場合は、4つのオプションがあります.そのうち2つはすでに知っていますが、他の2つはまだ知らないかもしれません.
void TakesCharStar(const char* s); // C
void TakesString(const string& s); // (C++17 ) C++
void TakesStringView(absl::string_view s); // Abseil C++
void TakesStringView(std::string_view s); // C++17 C++
関数呼び出し時にすでに対応するフォーマットの文字列が存在し、前の2つの方法が最適である.しかし、タイプ変換が必要な場合はどうすればいいですか(
const char*
からstring
に変換するか、逆です).string
をconst char*
に変換するには、(効率的だが不便な)関数c_str()
が必要です.void AlreadyHasString(const string& s) {
TakesCharStar(s.c_str()); //
}
Callers needing to convert a const char* to a string don’t need to do anything additional (the good news) but will invoke the creation of a (convenient but inefficient) temporary string, copying the contents of that string (the bad news):
const char*
をstring
に変換するには、追加の操作(良いメッセージ)は必要ありませんが、元の文字列の内容(悪いメッセージ)をコピーする一時文字列を作成します.void AlreadyHasCharStar(const char* s) {
TakesString(s); // s
}
どうやって解決しますか?
Googleは、
string_view
を使用して文字列パラメータを受け入れることを推奨します.このタイプはC++17よりも早いです.C++17環境ではstd::string_view
を使用し、非C++17環境ではabsl::string_view
を使用する必要があります.string_view
型の変数は、既存の文字リストをマッピングする「ミラー」として想像できます.より明確には、1つのstring_view
は、1つの文字データ区間を位置決めするために1つのポインタと1つの長さだけを含む.string_view
は、これらのデータを所有していないし、このストレージを変更することもできません.したがって、レプリケーションstring_view
は浅いコピーであり、文字列の内容はレプリケーションされない.string_view
は、const char*
およびconst string&
から暗黙的に構成することができる.また、string_view
は文字列をコピーしないため、string_view
を構築してもO(n)
のメモリコストはかかりません.const string&
でstring_view
を構成する場合、構造関数の時間的複雑さはO(1)
である.const char*
でstring_view
を構築すると、コンストラクション関数は自動的にstrlen()
を呼び出します(または、2パラメータ形式のstring_view
コンストラクション関数を使用することができます).void AlreadyHasString(const string& s) {
TakesStringView(s); // ; !
}
void AlreadyHasCharStar(const char* s) {
TakesStringView(s); // ; !
}
string_view
はその指向するデータを持っていないため、string_view
(const char*
のように)の指向する文字列にはこのstring_view
を超える生存期間が必要である.これは、string_view
を格納するには、string_view
が指向するデータの生存期間がstring_view
を超える生存期間を証明する必要があることを意味する.APIが単一の関数呼び出しで文字列データを使用し、その文字列データを変更する必要がない場合は、
string_view
を受信するだけで十分です.データを変更する必要がある場合や、後でデータにアクセスする必要がある場合は、string(my_string_view)
でstring_view
をC++文字列に明示的に変換する必要があります.既存のコード・ライブラリに
string_view
を追加することは、必ずしも正しいことではありません.関数内で文字列をstring
またはNULL
で終わるconst char*
を次のレベルの関数に渡す必要がある場合は、このレベルの関数パラメータをstring_view
に変更すると、非効率になる可能性があります.string_view
については、まずツールコードに採用し、さらに呼び出し側に徐々に普及することを推奨する.または、string_view
を新しいプロジェクトで統一的に使用します.追加の説明
string_view
オブジェクト自体が小さなメモリしか消費しないため、int
またはdouble
のように値で伝達されるべきである(参照、ポインタで伝達することに対して、訳者注).string_view
が指す文字列は、必ずしもstring_view
文字で終わるとは限らない.したがって、以下の表記は安全ではない:printf("%s
", sv.data()); //
しかし、以下の表記は可能である:printf("%.*s
", static_cast<int>(sv.size()), sv.data());
NULL
またはstring
のようにconst char*
:std::cout << "Took '" << s << "'";
string_view
またはconst string&
の最後のNULL
タイプのパラメータをconst char*
に直接変換することができます.唯一の例外は、関数アドレスを関数ポインタに割り当てると、関数ポインタのタイプが一致しないコンパイルエラーに遭遇することです.