誰がC ++のIOStreamsを設計/設計しましたか?それでも、今日の標準では十分に設計されていると見なされますか?[閉まっている]


127

まず第一に、私は主観的な意見を求めているように見えるかもしれませんが、それは私が求めているものではありません。このトピックに関する根拠のある議論を聞いてみたいです。


最近のストリーム/シリアライゼーションフレームワークがどのように設計されるべきかについて洞察を得ることを期待して、私は最近、Angelika LangerとKlaus Kreftによる本「Standard C ++ IOStreams and Locales」のコピーを手に入れました。私は、IOStreamsが適切に設計されていなければ、そもそもC ++標準ライブラリに組み込まれていないと考えました。

この本のさまざまな部分を読んだ後、IOStreamsが全体的なアーキテクチャの観点からのSTLなどと比較できるかどうか疑問になり始めています。たとえば、アレクサンダーステパノフ(STLの「発明者」)とのこのインタビューを読んで、STLに入った設計上の決定について学びます。

特に私を驚かせるもの

  • IOStreamsの全体的な設計の責任者は誰なのかは不明のようです(これについての背景情報をいくつか読みたいと思います。誰かが良いリソースを知っていますか?)。

  • あなたは、あなたがあなた自身のクラスとの入出力ストリームを拡張したい場合、あなたはかなり不可解とメンバ関数名を混乱とのインタフェースを取得入出力ストリームの直接の表面、例えば下に掘り下げ例えば一度getloc/ imbueuflow/ underflowsnextc/ sbumpc/ sgetc/ sgetnpbase/ pptr/ epptr(とそこのおそらくさらに悪い例)。これにより、全体的な設計と単一の部品がどのように連携するかを理解することが非常に難しくなります。私は上記でさえ本は助けにならないことくらい(私見)。


したがって、私の質問:

あなたは(実際には存在している場合、今日のソフトウェアエンジニアリングの基準で判断しなければならなかった場合であるこれらの任意の一般的な合意が)、うC ++の入出力ストリームは、まだうまく設計されたとみなされますか?(ソフトウェアの設計スキルを、一般的に古いと考えられているものから改善したくありません。)


7
興味深いハーブサッターの意見stackoverflow.com/questions/2485963/… :)ほんの数日間の参加後に、その男がSOを去ったのはあまりにも悪い
Johannes Schaub-litb

5
STLストリームにさまざまな懸念が見られる人は他にいますか?ストリームは通常、バイトのみを読み書きするように設計されています。特定のデータ型を読み書きできるのはフォーマッターです(フォーマットされたバイトを読み書きするためにストリームを使用する必要があるかもしれませんが)。両方を1つのクラスに混在させると、独自のストリームを実装することがさらに複雑になります。
mmmmmmmm

4
@rsteven、それらの懸念の分離があります。std::streambufバイトを読み書きするための基本クラスであり、istream/ ostreamは、ポインタをstd::streambuf宛先/ソースとして使用して、フォーマットされた入出力用です。
Johannes Schaub-litb

1
@litb:しかし、ストリーム(フォーマッター)が使用するstreambufを切り替えることはできますか?では、STLフォーマットを使用したいのですが、特定のstreambufを介してデータを書き込みたいですか?
mmmmmmmm

2
@ rstevens、ostream foo(&somebuffer); foo << "huh"; foo.rdbuf(cout.rdbuf()); foo << "see me!";
Johannes Schaub-litb

回答:


31

:いくつかの悪い考えのアイデアは、標準への道を見つけauto_ptrvector<bool>valarrayおよびexportちょうど少数を示すために、。だから私は必ずしもIOStreamsの存在を質の高いデザインのしるしとして受け取らないでしょう。

IOStreamsには、市松模様の履歴があります。これらは実際には以前のストリームライブラリを作り直したものですが、今日のC ++イディオムの多くが存在しなかったときに作成されたため、設計者には後知恵の利点がありませんでした。時間の経過とともに明らかになった1つの問題は、Cのstdioと同じくらい効率的にIOStreamsを実装することがほぼ不可能であるということです。ロケールの定義および実装方法。これについての私の記憶はかなりあいまいです、私は認めます。数年前、comp.lang.c ++。moderatedについて激しい議論の的となっていたことを覚えています。


3
ご意見ありがとうございます。comp.lang.c++.moderated貴重なものを見つけたら、質問の下部にあるアーカイブと投稿のリンクを閲覧します。-その上、私はあなたに同意しませんauto_ptr:Herb SutterのExceptional C ++を読んだ後、それはRAIIパターンを実装するときに非常に有用なクラスのようです。
stakx-2010年

5
@stakx:それにもかかわらず、それは非推奨になりunique_ptr、より明確でより強力なセマンティクスで置き換えられています。
UncleBens

3
@UncleBensにunique_ptrは右辺値参照が必要です。したがって、この時点auto_ptrで非常に強力なポインターです。
Artyom

7
しかし、auto_ptrコピー/割り当てのセマンティクスを台無しにしているため、バグの逆参照のニッチになる
Matthieu M.

5
@TokenMacGuy:これはベクトルではなく、ブール値を格納しません。これは多少誤解を招きます。;)
jalf

40

誰がそれらを設計したかについては、元のライブラリは(当然のことながら)Bjarne Stroustrupによって作成され、Dave Presottoによって再実装されました。これは、Andrew Koenigのマニピュレーターのアイデアを使用して、Cfront 2.0用にJerry Schwarzによって再設計および再実装されました。ライブラリの標準バージョンは、この実装に基づいています。

ソース「C ++のデザインと進化」、セクション8.3.1。


3
@ニール-ナットデザインのあなたの意見は何ですか?あなたの他の回答に基づいて、多くの人があなたの意見を聞きた
がり

1
@DVK私の意見を別の回答として投稿しました。

2
Bjarne Stroustrupへのインタビューのトランスクリプトを見つけたところ、IOStreamsの歴史の一部について言及しています:www2.research.att.com/~bs/01chinese.html(このリンクは現在一時的に壊れているようですが、試すことができますGoogleのページキャッシュ)
stakx-2010年

2
更新されたリンク:stroustrup.com/01chinese.html
FrankHB

28

今日のソフトウェアエンジニアリング標準で判断する必要がある場合(実際にこれらについて一般的な合意がある場合)、C ++のIOStreamsは適切に設計されていると見なされますか?(ソフトウェアの設計スキルを、一般的に古いと考えられているものから改善したくありません。)

いくつかの理由から、私はNOと言います:

不十分なエラー処理

エラー条件は、ではなく例外とともに報告する必要がありますoperator void*

「ゾンビオブジェクト」アンチパターンは、このようなバグの原因です。

フォーマットとI / Oの分離が不十分

ストリームオブジェクトは、必要かどうかにかかわらず、書式設定のための追加の状態情報を含める必要があるため、ストリームオブジェクトが不必要に複雑になります。

また、次のようなバグを書く確率も高くなります。

using namespace std; // I'm lazy.
cout << hex << setw(8) << setfill('0') << x << endl;
// Oops!  Forgot to set the stream back to decimal mode.

代わりに、次のようなものを書いた場合:

cout << pad(to_hex(x), 8, '0') << endl;

フォーマット関連の状態ビットはなく、問題もありません。

Java、C#、Pythonなどの「モダン」言語では、すべてのオブジェクトにI / Oルーチンによって呼び出されるtoString/ ToString/ __str__関数があることに注意してください。私の知る限り、C ++だけstringstreamが文字列に変換する標準的な方法として使用することにより、逆の方法でそれを行います。

i18nのサポートが不十分

Iostreamベースの出力は、文字列リテラルを断片に分割します。

cout << "My name is " << name << " and I am " << occupation << " from " << hometown << endl;

フォーマット文字列は、文全体を文字列リテラルに入れます。

printf("My name is %s and I am %s from %s.\n", name, occupation, hometown);

後者のアプローチは、GNU gettextのような国際化ライブラリに適応する方が簡単です。全文を使用すると、翻訳者により多くのコンテキストが提供されるためです。文字列フォーマットルーチンが並べ替え(POSIX $printfパラメータなど)をサポートしている場合は、言語間の単語の順序の違いもより適切に処理します。


4
実際、i18nの場合、変換ではパラメータの順序を変更する必要がある場合があるため、置換は位置(%1、%2、..)で識別する必要があります。そうでなければ、私は完全に同意します-+1。
peterchen 2010

4
@peterchen:それがPOSIX $指定子ですprintf
jamesdlin

2
問題はフォーマット文字列ではなく、C ++に型保証されていない可変引数があることです。
dan04

5
C ++ 11の時点で、タイプセーフな可変引数が追加されました。
Mooing Duck 2014

2
私は「追加の状態情報」が最悪の問題です。coutはグローバルです。それにフォーマットフラグを付けると、それらのフラグはグローバルになり、それらのほとんどの使用が数行の意図されたスコープを持っていると考えると、それはかなりひどいです。ostreamにバインドするが独自の状態を維持する「フォーマッタ」クラスを使用して、これを修正することができます。そして、COUTと物事は、一般的に...(それが可能であるとき)のprintfで行わ同じものに比べてひどい見える
greggo

17

これは純粋な意見なので、別の回答として投稿します。

入力と出力(特に入力)の実行は非常に難しい問題です。そのため、当然のことながら、iostreamライブラリには、十分な知識と完璧な知識がたくさんあります。しかし、どの言語のI / Oライブラリもすべてこのようなものであるように思えます。私は、I / Oシステムがそのデザイナーに畏敬の念を抱かせるような美しさを持つプログラミング言語を使用したことがありません。iostreamsライブラリには、特にCI / Oライブラリ(拡張性、タイプセーフなど)に比べて利点がありますが、優れたOOまたは一般的な設計の例として、それを保持している人はいないと思います。


16

C ++のiostreamについての私の意見は、特に自分のストリームクラスを実装することで実際に拡張を始めた後で、時間とともに大幅に改善しました。メンバ関数の名前が途方もなく貧弱であるにもかかわらず、拡張性と全体的なデザインに感謝し始めましたxsputn。とにかく、I / OストリームはCのstdio.hを大幅に改善したものだと思います。Cのstdio.hには型の安全性がなく、重大なセキュリティ上の欠陥がたくさんあります。

IOストリームの主な問題は、テキストフォーマッティングとシリアライゼーションという2つの関連するがやや直交する概念が混同することです。一方では、IOストリームは、人間が読める形式のオブジェクトのテキスト表現を生成するように設計されており、他方では、オブジェクトを移植可能な形式にシリアル化するように設計されています。これら2つの目標が同じ場合もあれば、深刻な不快感をもたらす場合もあります。例えば:

std::stringstream ss;
std::string output_string = "Hello world";
ss << output_string;

...

std::string input_string;
ss >> input_string;
std::cout << input_string;

ここで、入力として取得するものは、元々ストリームに出力したものではありません。これは、<<オペレーターが文字列全体を出力するのに対し、>>ストリームには長さ情報が格納されていないため、オペレーターは空白文字に遭遇するまでストリームから読み取るだけだからです。したがって、「hello world」を含む文字列オブジェクトを出力しても、「hello」を含む文字列オブジェクトのみを入力します。したがって、ストリームはフォーマット機能としての目的を果たしていますが、オブジェクトを適切にシリアル化してからシリアル化解除することに失敗しました。

IOストリームはシリアル化機能として設計されていないと言うかもしれませんが、その場合、入力ストリームは実際には何ですか?さらに、他の標準的なシリアル化機能がないため、実際には、I / Oストリームを使用してオブジェクトをシリアル化することがよくあります。boost::date_timeまたはを検討してください。演算子を使用してboost::numeric::ublas::matrix行列オブジェクトを出力する場合<<>>演算子を使用して入力すると、まったく同じ行列が得られます。しかし、これを実現するために、Boost設計者は列カウントと行カウントの情報をテキストデータとして出力に保存する必要があり、人間が読める実際の表示が損なわれました。繰り返しになりますが、テキストのフォーマット機能とシリアル化の厄介な組み合わせです。

他のほとんどの言語がこれら2つの機能をどのように分離しているかに注意してください。たとえば、Javaでは、フォーマットはtoString()メソッドを介して行われ、シリアル化はSerializableインターフェースを介して行われます。

私の意見では、最良の解決策は、バイトベースのストリームを標準の文字ベースのストリームと一緒に導入することでした。これらのストリームは、人間が読める形式/表示を考慮せずに、バイナリデータで動作します。これらは、C ++オブジェクトを移植可能なバイトシーケンスに変換するために、シリアル化/逆シリアル化機能としてのみ使用できます。


回答ありがとうございます。私はこれについて間違っている可能性がありますが、最後のポイント(バイトベースのストリームと文字ベースのストリーム)に関しては、これに対するIOStreamの(部分的な?)答えはストリームバッファ間の分離(文字変換、トランスポート、およびバッファリング)ではありません。およびストリーム(フォーマット/解析)?また、新しいストリームクラスを作成することはできませんでした。これは、(機械可読の)シリアライズとデシリアライズのみを目的としたクラスと、(人間が読める)フォーマットと解析に特化したその他のクラスです。
stakx-2010年

@stakx、はい、そして実際、私はこれを実行しました。std::char_traitsを取るために移植性に特化することができないので、それは思ったより少し厄介ですunsigned char。ただし、回避策があるため、拡張機能が再び役立つと思います。しかし、バイトベースのストリームが標準ではないという事実は、ライブラリの弱点だと思います。
Charles Salvia、

4
また、フォーマットの問題はから完全に分離されていないため、バイナリストリームを実装するには、新しいストリームクラス新しいバッファクラスを実装する必要がありますstd::streambuf。つまり、基本的に拡張しているのはstd::basic_iosクラスだけです。したがって、「拡張」が「完全に再実装する」領域に渡る行があり、C ++ I / Oストリーム機能からバイナリストリームを作成することは、その点に近づいているようです。
Charles Salvia

よく言って正確に私が疑ったもの。また、CとC ++の両方が特定のビット幅と表現を保証しないために非常に長くなっているという事実は、I / Oを実行する際に問題になる可能性があります。
stakx-2010年

オブジェクトを移植可能な形式にシリアル化するため。」いいえ、それらはそれをサポートすることを意図したものでは決してありませんでした
curiousguy '07 / 07/26

11

私は常にC ++ IOStreamsが不適切に設計されていることを発見しました。それらの実装は、新しいタイプのストリームを適切に定義することを非常に困難にします。また、io機能とフォーマット機能混在しています(マニピュレーターについて考えてください)。

個人的に、私が見つけたストリームの設計と実装の中で最も優れているのは、Adaプログラミング言語です。これはデカップリングのモデルであり、新しいタイプのストリームを作成する喜びであり、出力関数は、使用するストリームに関係なく常に機能します。これは、最も一般的な分母への感謝です。ストリームにバイトを出力すると、それだけです。ストリーム関数は、バイトをストリームに入れる処理をします。たとえば、整数を16進数にフォーマットするのは彼らの仕事ではありません(もちろん、クラスメンバーと同等の、タイプアトリビュートのセットがあり、フォーマットを処理するために定義されています)

ストリームに関してC ++が同じくらい簡単だったらいいのに...


私が言及した本は、基本的なIOStreamsアーキテクチャを次のように説明しています。トランスポート層(ストリームバッファクラス)と解析/フォーマット層(ストリームクラス)があります。前者はバイトストリームからの文字の読み取り/バイトストリームへの書き込みを担当し、後者は文字の解析または値を文字にシリアル化します。これは十分に明確に思えますが、これらの懸念が実際に本当に明確に分離されているかどうかはわかりません。ロケールが登場するとき。-新しいストリームクラスを実装することの難しさについても同意します。
stakx-2010年

「io機能とフォーマット機能を組み合わせる」<-それの何が問題になっていますか?それが図書館の要点です。新しいストリームの作成に関しては、ストリームの代わりにstreambufを作成し、streambufの周囲にプレーンストリームを構築する必要があります。
Billy ONeal

この質問に対する答えが、私が説明されたことのないことを理解させてくれたようです:ストリームの代わりにstreambufを派生する必要があります...
Adrien Plisson

@stakx:streambufレイヤーがあなたの言ったことを実行した場合、それで問題ありません。しかし、文字シーケンスとバイトの間の変換はすべて、実際のI / O(ファイル、コンソールなど)と混同されます。文字変換も行わずにファイルI / Oを実行する方法はありません。これは非常に残念です。
Ben Voigt

10

IOStreamsの設計は、拡張性と有用性の点で素晴​​らしいと思います。

  1. ストリームバッファー:boost.iostream拡張機能を確認してください:gzip、teeを作成し、ストリームを数行でコピーし、特別なフィルターを作成します。それなしではそれは不可能でしょう。
  2. ローカリゼーションの統合とフォーマットの統合。何ができるか見てください:

    std::cout << as::spellout << 100 << std::endl;

    印刷可能:「100」またはさらに:

    std::cout << translate("Good morning")  << std::endl;

    内蔵のロケールに応じて「Bonjour」や「בוקרטוב」を印刷可能std::cout

    iostreamが非常に柔軟だからといって、このようなことを行うことができます。

それはもっとうまくできるでしょうか?

もちろんできます!実際、改善できることがたくさんあります...

現在、から正しく派生させるのは非常に困難stream_bufferです。ストリームに追加のフォーマット情報を追加することは簡単ではありませんが、可能です。

しかし、何年も前に振り返ってみると、私はまだライブラリのデザインが十分に優れていて、多くのグッズを提供することができました。

常に全体像を見ることができるわけではありませんが、拡張機能のポイントを残すと、考えていなかったポイントでもはるかに優れた能力が得られます。


5
あなたはポイント2のためのあなたの例は、単にのようなものを使用するよりも良いだろう理由に関するコメントを提供することができますprint (spellout(100));し、print (translate("Good morning"));これは、I / Oからこの減結合は、フォーマットとして、良いアイデアのように見えるとi18nのでしょう。
Schedler、2010年

3
ストリームに組み込まれた言語に従って翻訳できるからです。すなわち:french_output << translate("Good morning"); english_output << translate("Good morning") 「Bonjourおはよう」
Artyom

3
ある言語では '<< "text" << value'を実行する必要があるが、別の言語では '<< value << "text"'を実行する必要がある場合、ローカリゼーションはprintf
Martin Beckett

@Martin Beckett知っています。Boost.Localeライブラリを見てください。そのような場合に何が起こりout << format("text {1}") % value、それはに翻訳され"{1} translated"ます。だからそれは正常に動作します;-)
Artyom

15
「できること」はあまり関係ありません。あなたはプログラマーであり、十分な努力で何でもできる。しかし、IOStreamsを使用すると、実行できることのほとんどを達成するのが非常に困難になります。そして、あなたは通常あなたのトラブルのためにひどいパフォーマンスを手に入れます。
jalf

2

(この答えは私の意見に基づいています)

IOStreamsは、同等の関数よりもはるかに複雑だと思います。C ++で書くときも、「古いスタイル」のI / Oにはcstdioヘッダーを使用しますが、これははるかに予測しやすいと思います。余談ですが(実際には重要ではありませんが、絶対的な時間差はごくわずかです)、IOStreamsはCI / Oよりも低速であることが多くの場合証明されています。


「機能的」というより「機能的」という意味だと思います。関数型プログラミングは、その一般的なプログラミングよりもさらに悪いコードを生成します。
Chris Becke

その間違いを指摘してくれてありがとう。修正を反映するように回答を編集しました。
Delan Azabani

5
IOStreamsは、ほぼ間違いなく、従来のstdioよりも低速でなければなりません。拡張可能で使いやすいI / Oストリームフレームワークを設計するタスクが与えられた場合、実際のボトルネックはファイルI / O速度またはネットワークトラフィック帯域幅である可能性が高いため、速度を二次的に判断するでしょう。
stakx-2010年

1
I / Oまたはネットワークでは、計算速度はそれほど重要ではないことに同意します。ただし、数値/文字列変換用のC ++はを使用してsstringstreamいることに注意してください。速度は重要ですが、副次的なものです。
Matthieu M.

1
@stakxファイルI / Oとネットワークのボトルネックは、「バイトごと」のコストの関数であり、非常に小さく、テクノロジーの向上によって劇的に低下しています。また、DMAの場合、これらのオーバーヘッドによって、同じマシン上の他のスレッドからCPU時間を奪うことはありません。したがって、フォーマットされた出力を実行している場合、効率的に実行する場合と実行しない場合のコストは簡単に大きくなる可能性があります(少なくとも、ディスクやネットワークによって隠されていない。アプリ内の他の処理によって隠されている可能性が高い)。
greggo 2015年

2

IOStreamを使用していると、いつも驚きます。

ライブラリはテキスト指向で、バイナリ指向ではないようです。これは最初の驚きかもしれません。ファイルストリームでバイナリフラグを使用しても、バイナリの動作を得るには不十分です。上記のユーザーCharles Salviaはそれを正しく観察しました:IOStreamsはフォーマットの側面(たとえば、浮動小数点数の制限された数字など)をシリアル化の側面(情報の損失を望まない場合)と混合します。おそらくこれらの側面を分離することは良いことでしょう。Boost.Serializationはこの半分を行います。必要に応じて、挿入機能と抽出機能にルーティングするシリアル化関数があります。すでにあなたは両方の側面の間の緊張を持っています。

多くの関数は、意味がわかりにくいものもあります(たとえば、get、getline、ignore、readです。区切り文字を抽出するものも、抽出しないものも、eofを設定するものもあります)。さらに、ストリームを実装するときの奇妙な関数名(xsputn、uflow、underflowなど)について言及する人もいます。wchar_tバリアントを使用すると状況はさらに悪化します。wifstreamはマルチバイトへの変換を行いますが、wstringstreamは行いません。wchar_tでは、バイナリI / Oはそのままでは機能しません。codecvtを上書きします。

cバッファI / O(つまりFILE)は、C ++のI / Oほど強力ではありませんが、透過性が高く、直観に反する動作はほとんどありません。

それでも、IOStreamに出くわすたびに、火のように蛾のように引き付けられます。多分本当に賢い人が全体的なアーキテクチャをよく見ていればそれは良いことでしょう。


1

質問の最初の部分に答えざるを得ません(だれがそうしたのですか?)。しかし、それは他の投稿で答えられました。

質問の2番目の部分(うまく設計されているか?)については、私の答えは「いいえ!」です。ここに私が何年もの間信じられないことに頭を振らせる小さな例があります:

#include <stdint.h>
#include <iostream>
#include <vector>

// A small attempt in generic programming ;)
template <class _T>
void ShowVector( const char *title, const std::vector<_T> &v)
{
    std::vector<_T>::const_iterator iter;
    std::cout << title << " (" << v.size() << " elements): ";
    for( iter = v.begin(); iter != v.end(); ++iter )
    {
        std::cout << (*iter) << " ";
    }
    std::cout << std::endl;
}
int main( int argc, const char * argv[] )
{
    std::vector<uint8_t> byteVector;
    std::vector<uint16_t> wordVector;
    byteVector.push_back( 42 );
    wordVector.push_back( 42 );
    ShowVector( "Garbled bytes as characters output o.O", byteVector );
    ShowVector( "With words, the numbers show as numbers.", wordVector );
    return 0;
}

上記のコードは、iostream設計のためにナンセンスを生成します。私の理解を超えたいくつかの理由で、それらはuint8_tバイトを文字として扱いますが、より大きな整数型は数値のように扱われます。Qed Badデザイン。

これを修正するために私が考えることができる方法もありません。タイプは、floatまたはdoubleの場合もあります。そのため、「int」にキャストして、文字ではなく数値がトピックであることを愚かなiostreamに理解させます。

私の返信への反対票を受け取った後、おそらくもう少し説明の言葉... IOStreamの設計は、アイテムがどのように扱われるかをプログラマーに伝える手段を提供しないため、欠陥があります。IOStream実装は任意の決定を行います(バイト数ではなく、uint8_tをcharとして扱うなど)。彼らは達成不可能を達成しようとするので、これはIOStreamデザインの欠陥です。

C ++は型の分類を許可していません-言語には機能がありません。is_number_type()またはis_character_type()IOStreamが適切な自動選択を行うために使用できるようなものはありません。それを無視して、推測で逃げようとすることは、ライブラリの設計上の欠陥です。

認められていますが、printf()は、一般的な "ShowVector()"実装でも同様に機能しません。しかし、それはiostreamの動作の言い訳にはなりません。しかし、printf()の場合、ShowVector()は次のように定義される可能性が非常に高くなります。

template <class _T>
void ShowVector( const char *formatString, const char *title, const std::vector<_T> &v );

3
非難は(純粋に)iostreamにありません。typedefuint8_tが何であるかを確認してください。本当にイワナですか?次に、それをイワシのように扱うためにiostreamを非難しないでください。
Martin Ba

また、汎用コードで確実に数値を取得したい場合は、ストリーム挿入演算子の代わりにnum_putファセットを使用できます。
Martin Ba

@Martin Baそうです-c / c ++標準では、「短いunsigned int」が何バイトあるかをオープンに保ちます。「unsigned char」は言語の特異性です。バイトが本当に必要な場合は、unsigned charを使用する必要があります。C ++では、「数値のみ」などのテンプレート引数に制限を課すこともできないため、ShowVectorの実装を提案されたnum_putソリューションに変更すると、ShowVectorは文字列のベクトルを表示できなくなります。;)
BitTickler 2014年

1
@Martin Bla:cppreferenceは、int8_tが正確に8ビットの幅の符号付き整数型であることを述べています.iostreamのtypedefとchar型のオーバーロードによって技術的に説明可能ですが、ガベージ出力が発生するのは奇妙であると著者に同意します。typedefではなく__int8をtrue型にすることで解決できた可能性があります。
gast128 2015

ああ、それは実際にはかなり簡単に修正できます:// std :: ostreamの修正。これは、unsigned / signed / char型のサポートを破壊し、//文字のように8ビット整数を出力します。名前空間ostream_fixes {inline std :: ostream&operator <<(std :: ostream&os、unsigned char i){return os << static_cast <unsigned int>(i); }インラインstd :: ostream&演算子<<(std :: ostream&os、signed char i){return os << static_cast <signed int>(i); }} //名前空間ostream_fixes
mcv

1

C ++のiostreamには、他の応答で指摘されているように、多くの欠陥がありますが、その防御に何か注意したいと思います。

C ++は、真剣に使用されている言語間で事実上ユニークであり、変数の入力と出力を初心者にとって簡単にします。他の言語では、ユーザー入力は型強制または文字列フォーマッターを含む傾向がありますが、C ++はコンパイラーにすべての作業を行わせます。C ++はこの点でそれほどユニークではありませんが、同じことが出力にもほぼ当てはまります。それでも、クラスやオブジェクト指向の概念を理解する必要がなく、C ++でフォーマットされたI / Oをかなりうまく行うことができます。繰り返しますが、もしあなたが初心者を教えているなら、それは大きなプラスです。

初心者にとってのこの単純さには代償が伴い、より複雑な状況でI / Oを処理するのは頭痛の種になる可能性がありますが、その時点までにプログラマーはそれらに対処できるほど十分に学習しているか、少なくとも十分に古くなっています。飲む。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.