web-dev-qa-db-ja.com

C ++ / STLでバイナリデータを格納する「適切な」方法

一般的に、C++でバイナリデータを格納する最良の方法は何ですか?オプションは、私が知る限り、文字列またはvector <char>の使用にかなり要約されます。 (特にC++を参照しているので、char *およびmalloc()の可能性は省略します)。

通常は文字列のみを使用しますが、欠落しているオーバーヘッドや、STLが内部的に行ってバイナリデータの健全性を損なう可能性のある変換があるかどうかはわかりません。誰かがこれにポインタ(har)を持っていますか?提案や好みは、何らかの方法で?

45
Sean Edwards

記憶が連続しているため、charのベクトルはNiceです。したがって、バークレーソケットやファイルAPIなどの多くのC APIで使用できます。たとえば、次のことができます。

  std::vector<char> vect;
  ...
  send(sock, &vect[0], vect.size());

そしてそれはうまくいきます。

基本的には、他の動的に割り当てられたcharバッファーと同じように扱うことができます。マジックナンバーやパターンを探して上下にスキャンできます。部分的に適切に解析できます。ソケットから受信する場合、データを追加するために非常に簡単にサイズを変更できます。

欠点は、サイズ変更が非常に効率的ではなく(サイズ変更または事前に慎重に割り当てる)、配列の前面からの削除も非常に効率が悪いことです。たとえば、データ構造の前部から一度に1つまたは2つの文字だけをポップする必要がある場合は、この処理の前に両端キューにコピーすることもできます。これにはコピーのコストがかかり、dequeメモリーは隣接していないため、C APIにポインターを渡すだけではできません。

結論として、データ構造とそのトレードオフについて理解してから、詳しく説明します。ただし、charのベクトルは、一般的に私が一般的に使用しているものです。

41
Doug T.

Std :: stringの最大の問題は、現在の標準では、基盤となるストレージが連続していることを保証していないことです。ただし、stringが連続していない既知のSTL実装はないため、実際にはおそらく失敗しません。実際、新しいC++ 0x標準は、std :: stringがstd :: vectorなどの連続したバッファーを使用することを義務付けることで、この問題を解決しようとしています。

文字列に対する別の議論は、その名前がバイナリバッファではなく文字列を含んでいることを示唆しているため、コードを読む人を混乱させる可能性があります。

そうは言っても、ベクターもお勧めです。

8
Tamas Demjen

私もこれにstd::stringを使用しており、問題は一度もありません。

昨日コードで鋭いリマインダーを受け取った1つの「ポインター」:バイナリデータのブロックから文字列を作成するときは、std::string(startIter, endIter)ではなくstd::string(ptr, offset, length)コンストラクター形式を使用しますフォーム-後者は、ポインタがCスタイルの文字列を指すと仮定し、最初のゼロ文字以降を無視します(指定されたlengthではなくlengthをコピーします文字)。

6
Head Geek

確かにcharのコンテナを使用する必要がありますが、使用するコンテナはアプリケーションによって異なります。

Charには、バイナリデータの保持に役立ついくつかのプロパティがあります。標準では、charデータ型の「パディング」は許可されていません。これは、バイナリレイアウトでガベージが発生しないことを意味するため、重要です。各文字は、正確に1バイトであることが保証されているため、幅が設定された唯一の単純な古いデータ型(POD)になります(他のすべては、上限または下限、あるいはその両方で指定されます)。

Charを格納する適切なstlコンテナに関する議論は、上記のDougによって適切に処理されています。どちらが必要かは、ユースケースに完全に依存します。特別なルックアップ、追加/削除、またはスプライスの必要なしに、繰り返し処理するデータのブロックを保持している場合は、ベクターをお勧めします。これにより、多くのライブラリと関数が想定するstd :: stringよりも意図が明確になります。 nullで終了するcスタイルの文字列を保持します。

3
Todd Gardner