yohhoyの日記

技術的メモをしていきたい日記

文字列取得バッファとしてのstd::string リターンズ

C++17(C++1z)標準ライブラリの文字列型 std::basic_string<charT> クラステンプレートでは、ポインタ型 charT* を返す 非const版 data メンバ関数が追加される。(ポインタ型const charT*を返すconst版 data メンバ関数C++98から存在している。)

まとめ:

  • C++98/03標準ライブラリでは仕様による保証が無いものの、実用上は &buf[0] を利用できる。*1
  • C++11/14標準ライブラリでは &buf[0] を利用する。
  • C++17(C++1z)標準ライブラリでは &buf[0] または buf.data() を利用する。

下記例のようなレガシーAPIに対して、配列の代わりに std::string オブジェクトを文字列取得バッファとして渡す方法。

// バッファsにNUL終端文字列を取得(size=バッファ長)
// 戻り値:バッファに格納された文字数(NUL文字を除く)
int legacy_get_string_api(char *s, int size);

(略)

// C++11準拠標準ライブラリ
#include <string>
std::string buf(BUFSIZE, '\0');
int len = legacy_get_string_api( &buf[0], BUFSIZE );  // OK
buf.resize(len);
文字列取得バッファとしてのstd::string

C++17(C++1z)準拠の標準ライブラリでは、&buf[0] の他に buf.data() という記述も可能となる。

// C++17(C++1z)準拠標準ライブラリ
#include <string>
std::string buf(BUFSIZE, '\0');
int len = legacy_get_string_api( buf.data(), BUFSIZE );  // OK
buf.resize(len);

ただしNUL終端文字が配置される文字位置*2に関しては、C++14以前と同様に書き換えが禁止されることに注意。

一方C++11標準規格によれば、文字位置 0≦n<size() ならば string オブジェクト外部から書き換え可能だが、NUL終端文字が格納されている n=size() 位置は書き換えが禁止される。

文字列取得バッファとしてのstd::string

提案文書P0272R0より該当箇所を引用(下線部は強調)。

charT* data() noexcept;
Returns: A pointer p such that p + i == &operator[i] for each i in [0,size()].
Complexity: Constant time.
Requires: The program shall not alter the value stored at p + size().

関連URL

*1:Herb Sutter氏によるコメント:"Short answer: In practice, on every implementation I know, std::string’s contents are contiguous and null-terminated."

*2:厳密に表現するならば、c_str() メンバ関数のために文字列末尾へ自動配置されるNUL終端文字の位置となる。std::string s("abc\0xyz"); の s[3] 位置のように、明示的に配置したNUL終端文字は自明に書き換えが可能。