2011-11-22 5 views
6

私はiostreamを読んで理解しています。ときどき私は、挿入子(<<)と抽出子(>>)は、テキストののシリアル化で使用することを意図していることが時々分かります。それはいくつかの場所ですが、この記事では良い例です:<iostream>宇宙、< <とは>>まだやるストリームのような方法に使用されている場合があるのバイナリデータとテキストを読み書きするインサータとエクストラクタ

http://spec.winprog.org/streams/

外いかなる原文の慣習にも従わない。 QtのQDataStreamで使用された場合例えば、彼らは、バイナリエンコードされたデータを書き込む:言語レベルでhttp://doc.qt.nokia.com/latest/qdatastream.html#details

は、< <と>>演算子はオーバーロードするようにプロジェクトに所属する(QDataStreamがないので、何が明らかに許容可能です) 。私の質問は、<iostream>を使用している人にとって、< <と>>演算子を使用してバイナリのエンコーディングとデコードを実装することは悪い習慣とみなされます。ディスク上のファイルに書き込まれて、ファイルをテキストエディタで表示および編集可能にする必要があるという期待がありますか?

常に他のメソッド名を使用し、それらをread()write()に基づいていなければなりませんか?あるいは、テキスト形式のエンコーディングは、標準ライブラリiostreamと統合するクラスが無視することができるデフォルトの動作としか考えられないでしょうか?


UPDATEは、この上の重要な用語の問題は(「バイナリ」VS用語「原文」とは反対に)「未フォーマット」対「書式設定」されたI/Oの区別のようです。

writing binary data (std::string) to an std::ofstream?

それはフォーマットされた出力 『「私の脳のようにそれを読み込むように私は、とにかくバイナリデータの< <を使用したくないだろう』 を言っ@ TomalakGeret'kalからのコメントがあります。私はこの質問を見つけましたあなたがやっていることではありません。もう一度、それは完全に有効ですが、私はちょうどそのように私の脳を混乱させませんでした。

ios::binaryを使用している限り問題は認められています。それは議論の「それに何も悪いことはありません」と強調しているようですが、私はまだこの問題に関する権威のある情報源は見ません。

+1

"テキストエンコーディング"は誤解を招く用語です。 「フォーマットされたI/O」はより適切です。 –

+0

あなたのフレームワークは何でもします。 –

+0

@KerrekSB "フォーマットされたI/O"が排除するものよりも、 "テキストエンコーディング"が何を排除しているのかがはっきりしています。 N個の32ビット整数を持つオブジェクトを持っている場合、 'write()'を使ってNの4バイトを出力し、その値に対応する4 * Nバイトを出力します...それでもまだフォーマットされていますか? – HostileFork

答えて

9

実際には、演算子<<>>はビットシフト演算子です。 I/Oのためにそれらを使用することは、厳密には既に誤って使用されています。しかし、その誤用はオペレータのオーバーロード自体と同じくらい古いものであり、今日のI/Oが最も一般的な用途であるため、I/O挿入/抽出演算子として広く認識されています。私は、iostreamsの先例がなかったら、誰もI/Oのためにそれらの演算子を使用しないと確信しています(特に、C++ 11では変数テンプレートがあり、iostreamのために解かれた演算子を使ってはるかにクリーンな方法)。一方、言語の観点から見ると、オーバーロードされたoperator<<operator>>は、それらが意味するものを意味することができます。

したがって、これらの演算子の使用はとなります。このため、iostreamクラスで動作する新しいオーバーロードと、iostreamのように動作するように設計された他のクラスで動作する新しいオーバーロードの2つのケースを区別する必要があります。

iostreamクラスの最初の新しい演算子について考えてみましょう。 iostreamクラスはすべてフォーマットに関するものです(逆のプロセス、「デフォーマッティング」と呼ばれることもあります);「レキシング」IMHOはエクストラクタがタイプを決定しないため、ここでは適切な用語ではありません与えられたタイプに従ってデータを解釈しようとするだけです)。生データの実際のI/Oを担当するクラスはstreambufsです。ただし、適切なバイナリファイルはではなく、で、内部の生データをダンプするだけのファイルです。テキストファイルのように(バイナリファイルには、それに含まれるデータの適切なエンコーディングが必要です)。特にファイルが異なるシステムで読み込まれることが予想される場合。したがって、フォーマットされた出力の概念は、バイナリファイルに対しても理にかなっています。書式設定が異なるだけである(例えば、整数値に対して最初に最上位のバイトを書き込む)。

iostream自体は、テキストファイル、つまりコンテンツがデータのテキスト表現として解釈されるファイルで動作するように設計されたクラスです。ビルトインビヘイビアの多くは、そのために最適化されており、バイナリファイルで使用すると問題を引き起こす可能性があります。明白な例は、入力が試行される前に、デフォルトでスペースはスキップされます。バイナリファイルの場合、これは明らかに間違った動作になります。また、ロケールの使用はバイナリファイルには意味がありません(バイナリロケールが存在する可能性があると主張するかもしれませんが、iostreamで定義されているロケールは適切なインタフェースを提供しているとは思えません)。したがって、iostreamクラスのバイナリoperator<<またはoperator>>の記述が間違っていると思います。

別のケースでは、バイナリ入出力用に別のクラスを定義します(実際のI/Oを実行するためにstreambufレイヤを再利用する可能性があります)。今では異なるクラスについて話しているので、上記の議論はそれ以上適用されません。ですから、質問は今です:I/O上のoperator<<operator>>は「テキスト挿入/抽出演算子」またはより一般的には「フォーマットされたデータ挿入/抽出演算子」と見なされますか?標準クラスではテキストのみを使用しますが、バイナリI/Oの挿入/抽出のための標準クラスは存在しないため、標準的な使用法では2つのクラスを区別できません。

私は個人的にバイナリの挿入/抽出が、この使用法が正当化されているテキストの挿入/抽出に十分近いと言います。また、意味のあるバイナリI/Oマニピュレータを作成することもできます。 bigendian,littleendianおよびintwidth(n)を使用して、整数を出力する形式を決定します。

それ以外にも、実際にはI/Oではないもの(そしてstreambufレイヤを使用することさえ考えられない場所)のために、これらの演算子を使用することもあります。私の意見では、データは異なる形式に変換されたり変換されたりしないため、演算子の誤用が既に行われています。それはちょうどコンテナに格納されています。

+0

長らくの回答ありがとうございました。あなたが作る点の中では、iostreamのインサータ/エクストラクタの「適切な」使用が、さまざまなプラットフォームアーキテクチャやコンパイラ実装間で転送できるファイルを生成することを示唆しているように聞こえますが...同じ意味を持ちます。この文脈で「フォーマットされた」とは何かを定義する信頼できる情報源がありますか?そうであれば、 '<<' and '>>は、(read()と.write()だけを使用するプロジェクトとは対照的に)何らかの形でその責任に結びついていますか? – HostileFork

+1

@HostileFork:実際には、適切なバイナリファイルには明確なフォーマットがあります。あなたがそれを別のプラットフォームから読むことができるという事実は自動的です。 '.read()'と '.write()'を使ったプロジェクトも、うまくいけば、明確に定義されたバイナリ形式を持っています。このルールの例外は、効果的にスワップとして使用される一時ファイルです。そのようなファイルは現在のプロセスでは生き残ることができず、別のファイルから読み取られることもないため、メモリダンプが含まれている可能性があります。バイナリファイルを書くことを意図した施設が、ユーザが適切なバイナリファイルを書くのを助けるならば、明らかに良い考えです。 – celtschk

+0

詳細な返答のために賞金が授与されました。私はまだ "答え"に少し不安定で、私はまだ水が少し泥だと感じているので、私はそれを宣言するのを延期して、おそらく自分自身を書くかもしれません。 iostreamを把握したいと思っている初心者への指導を本当に掘り起こすのは難しいです。誰も「これは良いコードですよ、このようにしてください」、あるいは「これは悪いコードです。 。 – HostileFork

4

標準でのiostreamの抽象化は、テキスト形式のデータストリームである のものです。非テキスト形式のサポートはありません。 これはiostreamsの抽象化です。 抽象化がバイナリ形式の別のストリームクラスを定義していても、 というのは間違っていませんが、iostreamでこれを行うと、既存のコードが破損する可能性があります。 では機能しません。

+0

私の質問は、 '<<' and '>>'演算子があなたのプロジェクトに属していることを受け入れることを前提としていました(したがって、 'QDataStream'がやっていたことは受け入れられます)。私は私の質問は、iostreamインサータとエクストラクタを実装して、ディスク上のファイルに書き込んでファイルを表示可能にし、テキストエディタで編集可能にする必要があると言う人が多いと思う。 – HostileFork

+1

iostream以外のストリームでバイナリ形式に '<<' and '>>'を使うことは問題ありません。問題はiostreamの意味を変えています。 –

+0

しかし...誰が言ってるの?上記の@KerrekSBに関する私のコメントに注目してください。彼は、実装整数の 'write()'が "フォーマット"されていないことを示唆しています...しかし、エンディアンを修正し、クロスプラットフォームで動作する非常に具体的な4バイトパターンを書いたらどうでしょうか?仕様書や標準仕様書では、iostreamの演算子を使用してオブジェクトをそのように直列化してはならないと書かれています。 – HostileFork

3

オーバーロードされた演算子>>および< <は、フォーマットされたIOを実行します。残りのIO関数(put、get、read、writeなど)は、書式なしのIOを実行します。フォーマットされていないIOは、IOライブラリが、その入力用の符号なし文字のシーケンスであるバッファのみを受け入れることを意味します。このバッファには、テキストメッセージまたはバイナリコンテンツが含まれている可能性があります。バッファを解釈するのはアプリケーションの責任です。しかし、フォーマットされたIOはロケールを考慮に入れます。テキストファイルの場合、アプリケーションが実行される環境によっては、入出力操作でシステム固有のテキストファイル形式に適合させるために特殊な文字変換が行われることがあります。ほとんどのUNIXベースのシステムなどの多くの環境では、ファイルをテキストファイルまたはバイナリファイルとして開くことに違いはありません。ご自分のタイプの演算子>>と< <をオーバーロードすることができます。これは、ロケール情報なしでフォーマットされたIOを自分のタイプに適用できることを意味しますが、それはちょっと難しいことです。

+0

ロケールの問題を「書式設定」の定義において重要な区別として提起することは興味深いことです。しかし、私はまだ「良い」、「悪い」練習が何であるかを正確に理解しようとしています。コントラストを説明するためのサンプルコードを見つけたり作成したりできると思いますか? – HostileFork

関連する問題