2017-01-05 4 views
4

のstd ::文字列:: c_str&ヌル終了

私はその明確にするため、この記述を好き:

ヌルで終了する配列 (つまりC文字列)を含む配列へのポインタを返します。 文字列オブジェクトの現在の値を表します。この配列には、文字列オブジェクトの値を構成する文字の同じシーケンス と最後にnull文字( '\ 0')を付加する が含まれています。

ただし、この機能の目的に関するいくつかの点はまだ不明です。

あなたはc_strを呼び出すと、ホストオブジェクト(std::string)の内部char配列に格納された文字列の末尾に\0文字を追加するかもしれないと思っために許されることができます:

s[s.size+1] = '\0' 

しかし、それはそうですstd::stringオブジェクトはヌルでもc_strを呼び出す前に、デフォルトで終端されている: enter image description here

定義を見た後:

const _Elem *c_str() const _NOEXCEPT 
{ // return pointer to null-terminated nonmutable array 
    return (this->_Myptr()); 
} 

文字配列の末尾に\0を追加するコードはありません。限り、私はc_strちょうどbegin()のような配列の最初の要素に格納されているcharへのポインタを返すと言うことができます。私は、内部配列が終了していることをチェックするコードも見ていません。\0

何か不足していますか?

+2

C++ 2003 StandardとC++ 2011 Standardの違いを見逃しました。クラスstd :: stringのC++ 2011 Standardオブジェクトの前に、終了ゼロのない文字列を格納することができます。 –

+0

1.文字列が作成または変更されている間に自動的にゼロが追加されます。 2.文字列定数 "123456789"は常にASCIIZで、末尾にゼロの文字があります。 –

+3

明らかに、関数 'c_str()'は、呼び出されるたびに配列の最後に0を付加しません。新しい配列を割り当てる必要があり、呼び出し元(おそらくあなた)は毎回それを割り当てなくてはなりません時間と再び... –

答えて

4

C++ 11より前では、std::string(またはテンプレートクラスstd::basic_string - そのうちのstd :: stringはインスタンス化です)は、末尾に'\0'を格納する必要はありませんでした。 data()c_str()メンバ関数の異なる仕様に反映されています。は、'\0'c_str()で終了する必要はありませんでした。'\0'のコピーを返しましたが、同様に、簡単にするために、いくつかの実装はとにかく末尾'\0'を追加することにした内部末尾'\0'を格納しないための要件(保存されたデータの終わりを過ぎて文字にアクセスすると、未定義の動作でした)...と、。

C++で基本的に、data()メンバ関数は、c_str()と同じ効果を与えるように指定されました(つまり、返されるポインタはfi末尾が'\0'の配列の最初の文字。その結果、配列上の'\0'の末尾にdata()が返され、結果として内部表現が返される結果になります。

これはC++ 11と一貫しています。クラスの不変量の1つが末尾に'\0'です(つまり、コンストラクタがそうであることを保証します。文字列を変更するメンバ関数は、すべてのパブリックメンバー関数がそれを真に信頼することができます)。

あなたが見ている動作は、C++ 11より前のC++標準と矛盾していません。厳密に言えば、std::stringの前にC++ 11は末尾を維持する必要はありませんでしたが、同様に、実装者はこれを行うこともできます。

1

c_strはnullで終了するcstringを返す必要があります。関数がヌルターミネータを追加しなければならないと言うことは何もありません。ほとんどの実装(と私はすべて標準に準拠したいと思います)は、文字列自体で使用される基底のバッファにヌルターミネータを格納します。この理由の一つは、

std::string s; 
assert(s[0] == '\0'); 

は、文字列が今string[string.size()]でヌルターミネータを返すために必要とされるため動作するようにしていることです。文字列がNULLターミネータを格納していない場合、[]は、それがsize()にあるかどうかを確認するために境界チェックを行う必要があり、\0を返す必要があります。

6

null文字が既に存在するため、シーケンスの最後に'\0'を追加するコードは表示されません。 c_strの実装は新しい配列へのポインタを返すことができないので、配列はstd::stringオブジェクト自体に格納されなければなりません。したがって

、あなたはこれを実装するための2つの有効なアプローチがあります。

  1. を常に'\0'を追加し、必要に応じて文字列のコピーを作成し建設上の文字の_Myptr()配列の末尾に'\0'を保存、または
  2. c_str()が呼び出されたときに、デストラクタでそのコピーを削除します。

_Myptr()c_str()に返すことができますが、各文字列に余分な文字を保存することはありません。 2番目のアプローチでは、std::stringオブジェクトごとに余分なポインタが必要なので、最初のアプローチは安価です。

関連する問題