C++1z(C++17)標準ライブラリ文字列std::string
と文字列ビューstd::string_view
において、data
メンバ関数が返すメモリ領域とヌル終端文字列の関係についてメモ。
まとめ:
string
に “非const版”data
メンバ関数 が追加され、変更可能なヌル終端文字列を返す。(→id:yohhoy:20160327)string_view
のdata
メンバ関数は、NUL文字('\0'
)で終端される保証のない読取専用メモリ領域を返す。string_view
は文字列の “ビュー” に過ぎないため、有効範囲[data(), data() + length())
を超えた*(data() + length())
はNUL文字でない可能性がある。*1string
/string_view
のdata
メンバ関数戻り値は意味が異なるため、文字列参照型(const string&
)から文字列ビュー型(string_view
)への単純置換には注意が必要。(→id:yohhoy:20171113)- ヌル終端文字列の取得に
string::c_str
メンバ関数を利用していれば、存在しないstring_view::c_str
呼び出しがコンパイルエラーとして検出される。C++11以降のstring::data
メンバ関数仕様に依存したソースコードのみ影響を受ける。(→id:yohhoy:20120601)
const修飾あり | const修飾なし | |
---|---|---|
string (C++14以前) |
読取専用ヌル終端文字列 戻り値型= const char* |
読取専用ヌル終端文字列 戻り値型= const char* |
string (C++1z以降) |
読取専用ヌル終端文字列 戻り値型= const char* |
変更可能なヌル終端文字列 戻り値型= char* |
string_view |
読取専用メモリ領域 NUL文字終端の保証なし 戻り値型= const char* |
読取専用メモリ領域 NUL文字終端の保証なし 戻り値型= const char* |
ヌル終端文字列を要求するレガシー関数(下記コードではstd::puts
)に対して、string_view::data
メンバ関数を組み合わせると予期しない結果をもたらす。
// 文字列参照型の引数 void func(const std::string& s) { std::puts(s.data()); // OK: "DEF"を出力 // または std::puts(s.c_str()); // OK: "DEF"を出力 } std::string str = "abcDEFghi"; func(str.substr(3, 3)); // 部分文字列"DEF"を渡す
// C++1z(C++17) // 文字列ビュー型の引数 void func_strview(std::string_view sv) { std::puts(sv.data()); // NG: "DEFghi"を出力 std::string s{sv}; // std::stringへコピーすれば... std::puts(s.c_str()); // OK: "DEF"を出力 } std::string_view sv1 = "abcDEFghi"; func(sv1.substr(3, 3)); // 部分文字列ビュー"DEF"を渡す
関連URL