yohhoyの日記

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

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

C++1z(C++17)標準ライブラリの文字列型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++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++1z準拠の標準ライブラリでは、&buf[0]の他にbuf.data()という記述も可能となる。

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

2021-02-03追記:正式なC++17ライブラリ仕様ではLWG 2475修正が適用され、std::basic_string<charT>内部バッファのNUL終端文字位置へのNUL終端文字上書きに限って特例許容される。詳細はyumetodoさんによる こちらの記事 を参照のこと。
ただし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終端文字は自明に書き換えが可能。