2012-05-13 2 views
8

私の同僚のコードをこのように見えた:C++で[length()]という文字列を入力しても問題ありませんか?

void copy(std::string const& s, char *d) { 
    for(int i = 0; i <= s.size(); i++, d++) 
    *d = s[i]; 
} 

彼のアプリケーションがクラッシュし、私は条件が唯一s.size() - 1まで行く必要があるため、これは、範囲外のsにアクセスするので、それがあると思います。

しかし、私の隣にいる他の人は、これが合法であるということについて過去に議論があったと言います。誰も私のためにこれをクリアしてもらえますか?

+0

私はターゲットポインタについてもっと気にします。なぜ関数はサイズパラメータを取っていないのですか? – LaC

+0

おそらく 's.c_str()'をコピーしようとするべきでしょう。 – Yaniro

+3

おそらく 'd'の容量が間違っています – Abyx

答えて

10

はのは、それが問題をに向け思われるものとは何の関係もありませんので、*dが無効であること可能性について脇に置くましょう。

const_reference operator[](size_type pos) const; 
reference operator[](size_type pos); 

戻り値:pos < size()場合は、data()[pos]を返し

C++ 03標準ではstring::operator[]()の以下の説明(21.3.4 "basic_string要素へのアクセス")を有します。それ以外の場合、pos == size()の場合、constバージョンはcharT()を返します。それ以外の場合、動作は未定義です。

のコード例ではsconstあるので、行動が明確に定義されているとs[s.size()]はnull文字を返します。ただし、sconst stringでない場合、動作は未定義です。

C++ 11は、constバージョンのこの奇妙なボールの振る舞いを、このエッジケースでは非constバージョンと大きく異なるように扱います。 C++ 11 21.4.5 "basic_string要素へのアクセスは、" 言う:

const_reference operator[](size_type pos) const; 
reference operator[](size_type pos); 

が必要です:pos <= size()

戻り値:*(begin() + pospos < size()場合、値charT()有するT型のオブジェクトへの参照さもなければ 。参照される値 は修正されないものとする。

だから、C++ 11コンパイラのため、動作がstringconstであるか否かが明確に定義されています。

質問とは無関係に、C++ 11では「参照される値は変更されない」と言われていますが、ちょっと奇妙なことがわかります。その文節がpos == size()の場合にのみ適用されるかどうかはわかりません。 s[i] = some_character;のようなものを実行する既存のコードがたくさんあると確信しています。ここで、sは非const std:stringi < s.size()です。これは未定義の動作ですか?私はその句が特別なケースのcharT()オブジェクトにのみ適用されると考えています。

もう1つの興味深い点は、s[s.size()]のために返されるオブジェクトのアドレスが、s[s.size() - 1]のために返されるオブジェクトのアドレスに何らかの形で関連していることを要求していないようです。言い換えれば、返されたcharT()参照が文字列データの最後に連続している必要はないようです。私はこれが、実装者に、望むならば、そのセンチネル要素の単一の静的コピーへの参照を返す選択肢を与えることではないかと考えています(C++ 11の "変更しない"という制限もあります。場合)。

+0

しかし、 'at'は' size() 'をインデックスとして呼び出すことができないのが面白い。 –

+0

深度分析に感謝します。 –

7

cppreference says this:

reference  operator[](size_type pos); 

const_reference operator[](size_type pos) const; 

pos==size()場合、

  • CONSTバージョン値チャート()(ヌル文字)の文字への参照を返します。 (C++ 11まで)
  • 両方のバージョンは、値CharT()(ヌル文字)を持つ文字への参照を返します。非const参照を使用してヌル文字を変更すると、未定義の動作が発生します。 (C++ 11以降)

null文字を変更しない限り、問題ありません。

+0

OPのコードはstd :: stringを変更しようとしません。文字列から読み込み、char配列に配置しようとします。 –

+4

ちょうど明白です - もし 's'が' const'でなければ 's [s.size()]'へのアクセスは未定義です。質問のコード内のアクセスはOKです's'は' const'です(pre-C++ 11コンパイラ用)。ヌル文字が変更されているかどうかは 's'が' const'であるかどうかとは無関係です。もちろん、 '* d 'が無効である可能性については何も述べていません。 –

+1

標準適合性を証明するためにウェブサイトを引用することは面白いと思うが、少し掘り下げて;) –

0

あなたは(あなたの同僚のコードが同様に終了\0をコピーしようと)そのようにそれをしたい場合は、

  • c_str()を使用することができます。
  • ループをi < s.size()で使用し、後で手動で\0を追加します。

編集:配列dがあふれすることができる(またはそれも割り当てられていない場合があります):
まあ、他の回答から判断すると、私はAbyxさんのコメントが正しいことを今考えるともっと傾いています。最初に確認してください。
\0もコピーしてください。インデックスstd::string::size()で「要素」をアクセスするときだけでなく振る舞いを定義しているかどうかをstd::string operator[]()

関連する問題