2012-11-26 2 views
5

Visual Studio C++ 2010でbasic_string::append (iter, iter)が明らかにstd::copyを使用して実装されていないことがわかりました。basic_string :: append(iter、iter)がstd :: copyを呼び出さないのはなぜですか?

最初の質問:

は、今、私が一緒に、より効率的なブロック単位のコピーを提供するために、私のイテレータ型用std::copyの最適化されたオーバーロードして、自分のイテレータ型を実装するとします。 basic_string::appendにこのような最適化を利用する方法はありますか?appendのオーバーロードとは別に、

basic_string::append (iter, iter)が文字単位でコピーしない可能性はありますか?

(私自身の実装のための出発点として)2番目の質問:

は有効であると、次の保証されていますか?

std::string t ("JohnB"); 
std::string s; 
s.reserve (10); 
std::copy (t.begin(), t.end(), s.begin()); 
s.push_back ('\0'); 

back_inserterをよく使うべきですか? back_inserterを使用している場合 - どのように文字のコピーを避けることができますか?

+0

あなたの2番目の質問に答えるには、 'reserve()'に続けて 'copy()'が間違いなく__not valid__です。その理由を調べるには、コピーの後に 's.size()'を表示してください。 – Blastfurnace

+0

@Blastfurnace:しかし、 'resize()'の後に 'copy()'が続きます。 –

+0

'resize'に続いて' copy'はどうでしょうか? – JohnB

答えて

2

std::basic_string<cT, ...>::append()の定義は、それが最終的に過負荷(21.4.6.2 [文字列::追記]第7項)に到着する前に数時間を委任し続ける:この時点で

basic_string& append(const charT* s, size_type n);

元のイテレータが残っていないことは明らかです。

効果:append(basic_string(first, last))に相当するものは、あなたがappend()に渡されたかもしれない入力イテレータに何が起こるか疑問に思う場合は、述べて同項のパラグラフ17で過負荷によって除去してしまいました。

何らかの中間状態である。スタンダードライブラリが、標準で文字どおり指定されているように実装されている場合、明らかにstd::copy()への呼び出しはありません。

とにかく、あなたのオーバーロードされたバージョンはstd::copy()を実際に見ることはできません。どのようなライブラリーを行うことは今、他の興味深いビットは

template <typename InIt> 
std::basic_string<cT, ...>& std::basic_string<cT, ...>::append(InIt begin, InIt end) { 
    if (is_forward_iterator<begin>::value) { 
     this->reserve(this->size() + std::distance(begin, end)); 
    } 
    std::copy(begin, end, back_inserter_without_capacity_check<InIt>(*this); 
} 

の道徳的等価です。これは、それが実装する方法であっても、それは本当にstd::copy()に関してお手伝いをしません! std::copy()を部分的に特化することはできません(任意の関数テンプレートを部分的に特殊化することはできません)。ターゲットイテレータのタイプは定義されていません(上記の実装では、の場合、それ以外の場合は、std::back_inserter()と同じになります。

+0

しかし、実装が 'namespace stdを使用していた場合。 ...;コピー(begin、end、...) 'を実行すると、イテレータクラスのネームスペースのイテレータクラス(第1引数と第2引数)に' copy'を定義することができ、 'copy'の私のバージョンはADLによって検出されます。私は本当に 'append(const char *、size_type)'への委譲の標準実装は良い考えであるとは思わない。文字配列を最初に構築する必要があるからだ。 – JohnB

+0

私はそれがまったくいいアイデアだと主張していません。私が言っているのは、これは標準が言っていることであり、実装が実際には 'copy()'のバニラのADL-findableバージョンを呼び出さないことを意味します。また、両方の入力イテレータに特化した 'copy()'が見つかった場合は、出力イテレータに特化した 'copy()'のバージョンであいまいさを生む可能性があります。これを避け、 'copy()'をカスタマイズポイントと見なさない方がより合理的です。 –

5

文字列クラスには、それに含まれる文字に対して実行できる操作を定義する独自の特性クラスがあります。

charをコピーするには、basic_string<char>std::char_traits<char>::copy(より一般的なstd::copyの代わりに)を使用します。おそらく標準のCライブラリのmemcpy関数に対応しています。

+0

'std :: copy(const char *、const char *、char *)'のオーバーロードも 'memcpy'にマップされます。 –

+0

非常にうまくいくかもしれませんが、 'std :: string'は' char_traits'クラスを経由しなければならないので、(少なくとも、少なくとも)それを使うことはできません。 –

+0

実際には、 'std :: basic_string'クラスのテンプレートが' cT const * 'によって指される文字列の長さを決定する必要があるときに' traits :: length() 'への直接の参照しか見ることができません。 :: eq() 'と' traits :: compare() 'を使って文字の値を比較します。 'traits :: copy()'を呼び出す必要はありません! –

関連する問題