なぜstd :: stringに直面して非常に多くの文字列クラスがあるのですか?


56

多くのより大きなC ++ライブラリが独自の文字列型を作成することになります。クライアントコードでは、(ライブラリからいずれかを使用する必要があるのいずれかQStringCStringfbstringまたは時間のほとんどが含まれている(標準タイプと1の間のライブラリの使用を変換しておく、私は誰もがいくつかに名前を付けることができます確信しているなど)少なくとも1つのコピー)。

だから、特定の誤機能または何か悪い点がありますかstd::stringauto_ptrセマンティクスが悪いように)?C ++ 11で変更されましたか?


32
「Not Invented Here Syndrome」と呼ばれます。
キャットプラスプラス

10
@CatPlusPlus QStringおよびCStringは、どちらもstd :: stringより前のものです。
ロボット

8
@Cat Plus Plus:この症候群はJava Stringクラスに影響を与えないようです。
ジョルジオ

20
@Giorgio:Javaプログラマーは、言語の欠陥を回避するための回避策の考案に忙しすぎて、文字列クラスを心配しません(AndroidはちなみにStringを再発明しました)。
キャットプラスプラス

9
@Giorgio:これはおそらく、Javaのハードコードされた構文サポートjava.lang.String(演算子のオーバーロードの欠如など)が他のものを使用するのが苦痛になるためです。
メカニカルカタツムリ

回答:


57

これらのより大きなC ++ライブラリのほとんどは、std::string標準化される前に開始されました。その他には、UTF-8のサポートやエンコード間の変換など、後ほど標準化された、またはまだ標準化されていない追加機能が含まれます。

それらのライブラリが今日実装されていれば、おそらくstd::stringインスタンスを操作する関数とイテレータを書くことを選択するでしょう。


5
UTF-8のサポートは、C ++ 98以降標準化されています。そのような不便で部分的に実装が定義された方法で、だれもそれを使用できないように見える
-AProgrammer

9
@AProgrammer:charUTF-8コードポイントを保持するのに十分な大きさであることが保証されています。私の知る限り、それはC ++ 98が提供する唯一の「サポート」です。
ベンフォークト

4
@AProgrammer:そのサポートは本当に役に立たない。
DeadMG

4
@AProgrammer すべてのUnicodeコードポイントを表すのに十分な大きさでwchar_tないため、そのロケールは間違いなく壊れています。さらに、UTF-8を排他的に使用するという非常に説得力のある議論が行われた場合、有害である と見なされるUTF-16についてのこの全体の議論がありました…
Konrad Rudolph

6
@KonradRudolph、そこで壊れているのはロケールシステムではありません(wchar_tの定義は「サポートされている任意の文字セットに十分な幅」です)。16ビットwchar_tにコミットしたシステムは、同時にUnicodeをサポートしないことをコミットしました。さて、犯人はユニコードであり、最初に16ビット以上を必要とするコードポイントを使用しないことを保証し、次にシステムが16ビットwchar_tにコミットし、次にユニコードスイッチングが16ビット以上を必要とすることを保証しました。
AProgrammer

39

文字列はC ++の大きな恥ずかしさです。

最初の15年間は、文字列クラスをまったく提供しません。すべてのプラットフォームのすべてのコンパイラーとすべてのユーザーが独自のクラスを作成するように強制します。

次に、完全な文字列操作APIなのか、STD charコンテナなのか、std :: Vectorにあるものを複製するアルゴリズムと異なるものを使用するなど、混乱するものを作成します。

replace()やmid()のような明らかな文字列操作には、1つのページに収まるように新しい「auto」キーワードを導入する必要があるイテレータの混乱が含まれ、ほとんどの人が言語全体を放棄するようになります。

そして、あなたはユニコード「サポート」とちょうどarghh .....であるst :: wstringを持っています

<暴言>ありがとう-気分が良くなりました。


12
@DeadMG-はい。1998年に標準化されました。発明されてから15年後、MSFTでも使用されてから6年後です。はい、イテレータは配列とリストを同じように見せるための便利な方法です。文字列操作を行うための明らかな方法だと思いますか?
マーティンベケット

3
C with Classesは1983年に発明されました。C++ではありません。唯一の標準ライブラリは、標準によって決定されたものです。奇妙なことに、標準を取得して初めて発生する可能性があるため標準ライブラリの可能な限り早い日付は1998年です。私は、イテレータが範囲と比較して吸い込むという事実に賛成していますが、それは実際にはに固有のものではありませんstd::string。1983年にStringクラスがなかったからといって、それらのクラスが増えたわけではありません。
-DeadMG

8
私は...入出力ストリームはC ++の大きな恥ずかし思っていた
ダグT.

18
@DeadMG人々は1998年よりも何年も前から「C ++」と呼ばれるものを使用していました。1985年に「C ++」と呼ばれるものを使用して最初のプログラムを作成しました。これに先立ち、コードを書いていて、どこかから文字列クラスを取得する必要がありました。これらのレガシコードベースを作成したら、標準を取得したときに、それらを正確に破棄したり、ゼロから書き換えたりすることはできませんでした。今、何をすべき起こったのは、cfrontの付属の文字列クラスがあったということです。
ロボット

8
@DeadMG-ISO証明書を取得するまで誰も言語を使用しなかった場合、ISOに到達することはないため、言語は使用されません。そこのx86アセンブラのためのISO規格はありませんが、私はプラットフォームを使用して満足している
マーティンベケット

32

実際、...にはいくつかの問題がありstd::string、C ++ 11では少し良くなりますが、先に進まないようにしましょう。

QStringまたCString古いライブラリの一部であるため、C ++が標準化される前に存在していました(SGI STLとよく似ています)。したがって、クラスを作成する必要がありました。

fbstring非常に具体的なパフォーマンスの問題に対処します。この規格はインターフェースを規定しており、アルゴリズムの複雑さは最小限を保証しますが、これが最終的に高速であるかどうかは実装品質の詳細です。fbstring特定の最適化があります(findたとえば、ストレージ関連、または高速)。

ここで引き起こされなかった他の懸念(vracで):

  • C ++ 03では、ストレージが連続していることは必須ではなく、Cとの相互運用性を潜在的に困難にします。C ++ 11はこれを修正します。
  • std::string エンコードを意識せず、UTF-8用の特別なコードはありません。UTF-8文字列を保存して、誤って破損するのは簡単です。
  • std::stringインターフェースが肥大化し、多くのメソッドがフリー関数として実装されている可能性があり、多くはインデックスベースのインターフェースとイテレーターベースのインターフェースの両方に適合するように複製されています。

5
懸念事項#1-C ++ 03 21.3.6 / 1 c_str()は、連続するストレージへのポインターを返すことを保証します。これにより、Cの相互運用性が確保されます。ただし、ポイント先のデータを変更することはできません。一般的な回避策には、の使用が含まれますvector<char>
ジョンディブリング

@JohnDibling:はい、そして別の制限があります:新しく割り当てられたストレージにコピーが発生する可能性があります(規格はそうしないとは言っていません)。もちろん、C ++ 11はコピーも防止しませんが、単純に実行できる&s[0]ため、もはや問題ではありません:)
Matthieu M.

1
@MatthieuM .:経由で取得したポインターは&s[0]、NULで終了する文字列を指すことはできません(c_str()最後の変更以降に呼び出されていない限り)。
ベンフォークト

2
@Matthieu:別のバッファは許可されていません。" c_str()戻り値:" 内のそれぞれのpようなポインタ。p + i == &operator[](i)i[0,size()]
ベンフォークト

3
また、注目に値するのは、彼らの正しい心の誰ももはやMFCを使用していないということです。したがって、CStringが現代のC ++の文字列クラスであると主張することは困難です。
DeadMG

7

ここに投稿された理由とは別に、別の1 バイナリ互換性もあります。ライブラリの作成者は、使用しているstd::string実装と、それと同じメモリレイアウトを使用しているかどうかを制御できません。

std::stringテンプレートであるため、その実装はローカルSTLヘッダーから取得されます。ここで、標準と完全に互換性のある、パフォーマンスが最適化されたSTLバージョンをローカルで使用していることを想像してください。たとえばstd::string、動的割り当てとキャッシュミスの数を減らすために、それぞれに静的バッファを挿入することを選択した場合があります。その結果、実装のメモリレイアウトやサイズは、ライブラリのものとは異なります。

レイアウトのみが異なるstd::string場合、ライブラリからクライアントに渡されたインスタンスの一部のメンバー関数呼び出し、またはその逆は失敗し、どのメンバーがシフトされたかに依存します。

サイズが異なる場合、std::stringメンバーを持つすべてのライブラリタイプは、ライブラリとクライアントコードでチェックしたときに異なるsizeofを持つように見えます。メンバーに続くデータメンバーstd::stringもオフセットがシフトし、クライアントから呼び出された直接アクセス/インラインアクセサーは、ライブラリ自体のデバッグ時に「OK」に見えても、ごみを返します。

ボトムライン-ライブラリとクライアントコードが異なるstd::stringバージョンで再度コンパイルされた場合、それらはうまくリンクしますが、厄介で理解しにくいバグが発生する可能性があります。std::string実装を変更する場合、STLからメンバーを公開するすべてのライブラリを再コンパイルして、クライアントのstd::stringレイアウトに一致させる必要があります。また、プログラマーは自分のライブラリーを堅牢にしたいので、std::stringどこでも公開されることはめったにありません。

公平のために、これはすべてのSTLタイプに適用されます。IIRCでは、メモリレイアウトが標準化されていません。


2
* nixプログラマでなければなりません。C ++バイナリ互換性はすべてのプラットフォームで同等ではありません。特にWindowsでは、データメンバーを含むNOクラスはコンパイラ間で移植可能です。
ベンフォークト

(私はPODのタイプを除き意味、そしてその後も、明示的な梱包要件が必要とされている)
ベン・フォークト

1
入力ありがとう
-gwiazdorrr

1
+1:ABIは、コンパイラが提供するクラスの独自バージョンを展開する大きな理由です。それだけで、これが受け入れられた答えであることを望みます。
トーマスエディング14

6

質問には多くの答えがありますが、ここにいくつかあります:

  1. レガシー。多くの文字列ライブラリとクラスは、std :: stringが存在する前に作成されました。

  2. Cのコードとの互換性のため。ライブラリstd :: stringは、CおよびC ++で機能する他の文字列ライブラリがあるC ++です。

  3. 動的割り当てを回避するため。ライブラリstd :: stringは動的割り当てを使用するため、組み込みシステム、割り込みまたはリアルタイム関連のコード、または低レベルの機能には適さない場合があります。

  4. テンプレート。ライブラリstd :: stringはテンプレートに基づいています。ごく最近まで、多くのC ++コンパイラのパフォーマンスが低いか、テンプレートのサポートがバグでさえありました。残念ながら、私は多くのカスタムツールを使用する業界で働いており、業界の主要なプレーヤーのツールチェーンの1つは、C ++を「公式に」100%サポートしていません(バグのあるものはテンプレートなどです)。

おそらく、もっと多くの正当な理由もあります。


2
「かなり最近」というのは、「Visual Studioでもかなり合理的なサポートを受けてから10年が経ちました」という意味ですか?
DeadMG

@DeadMG-Visual Studioは、世界で唯一の非準拠コンパイラではありません。私はビデオゲームに携わっており、リリースされていないハードウェアプラットフォーム用のカスタムコンパイラに取り組んでいることがよくあります(コンソールサイクルの数年ごと、または新しいハードウェアが登場するたびに起こります)。「かなり最近」とは、今日を意味します-現在、特定のコンパイラはテンプレートを十分にサポートしていません。私はNDAに違反することなく特定することはできませんが、現在、C ++サポート(特にテンプレートコンプライアンス)が「実験的」であると見なされるカスタムツールチェーンを備えたプラットフォームで作業しています。
アディサック

4

それは主にユニコードについてです。Unicodeの標準サポートはせいぜいひどく、誰もが独自のUnicodeニーズを持っています。たとえば、ICUは、想像できる限り最も不快なJavaから自動生成されるインターフェイスの背後にある、必要なすべてのUnicode機能をサポートします。良い時間。

さらに、多くの人々は異なるレベルのUnicodeサポートを必要としています。誰もが複雑なテキストレイアウトAPIなどを必要とするわけではありません。そのため、多くの文字列クラスが存在する理由は簡単にわかります。標準クラスは非常にひどく、誰もが新しいクラスとは異なるニーズを持っています。

私の意見では、これは主に1998年または2003年にユニコードのサポートを正しく提供しなかったC ++委員会のせいであり、C ++ 11では理解できなかったかもしれません。うまくいけば、C ++ 17でより良くなるでしょう。


こんにちは、C ++ 20です。Unicodeサポートはどうなったと思いますか?
までに通行人

-4

それは、すべてのプログラマーが証明するものを持っているためであり、1つの素晴らしい機能のために、独自の素晴らしい高速な文字列クラスを作成する必要性を感じています。それは通常少し余分なものであり、私の経験ではあらゆる種類の余分な文字列変換につながります。


7
これが本当だったなら、Javaのような言語で同様の数のString実装が見られることを期待しています。
ビルK

@BillK Java文字列は最終的なものなので、新しい機能を別の場所に配置する必要があります。

そして、私のポイントは、最終的なものでさえ、20年で誰もカスタム文字列の要素を書くのを見たことがありません(まあ、私は文字列連結のパフォーマンスを改善しようとしましたが、javaはあなたよりも文字列+文字列ではるかに賢いことがわかりましたd想像)
ビルK

2
@ビル:それは異なる文化に関係しているかもしれません。C ++は、低レベルの詳細を理解したい人を魅了します。Javaは、他の誰かのビルディングブロックを使用して仕事を終わらせたいだけの人を惹きつけます。(これは、いずれかの言語を使用することを選択した特定の個人に関する声明ではなく、言語のそれぞれの設計目標と文化に関する声明であることに注意してください)
ベンVoigt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.