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つはまだ知らないかもしれません.
    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に変換するか、逆です).stringconst 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*に直接変換することができます.唯一の例外は、関数アドレスを関数ポインタに割り当てると、関数ポインタのタイプが一致しないコンパイルエラーに遭遇することです.