1

最近、古い C スタイルの関数ではなく、標準の C++ ライブラリ関数を使用するように一部のコードを更新しようとしています。特に、私は次のことを試みました(簡単にするために人工的な作業例-コードが醜いことは知っていますが、問題を簡潔に示しています):

std::vector<int> vData;
vData.push_back(10990);
vData.push_back(11990);
vData.push_back(12990);
vData.push_back(13990);

unsigned char szBuffer[100];
memset(szBuffer,0,sizeof(szBuffer));

std::copy(vData.begin(),vData.end(),szBuffer);

これは、置き換えようとしているコードと同様に動作することを期待していました。

memcpy(szBuffer,&vData[0],sizeof(int)*vData.size());

しかし、コードをデバッグすると、私が書いたコードは、ベクトル内の 4 つの整数の完全なビット パターンではなくstd::copy、バッファーの最初の 4 バイトにのみ書き込みを行っていることが明らかです。unsigned char誰かが私が間違ったことを教えてもらえますか、それとも単にstd::copyこの方法では使用できず、そのままにしておくべきなのmemcpyでしょうか?

4

4 に答える 4

5

に固執しmemcpy、インテリジェントであり、関連する型を理解し、標準変換を使用してstd::copy正しく変換しています。無知です、それがあなたが望むものです。intunsigned charmemcpy

于 2012-10-24T10:47:06.310 に答える
2

これは、置き換えようとしているコードと同じように動作することを期待していました...

記述されているとおり、またはの要素との要素間の型の不一致が原因で、またはstd::copyのように動作することはできません。このタイプの不一致を克服する1つの方法は、それを:にキャストすることです。std::memcpystd::memmovestd::vector<int>unsigned char szBuffer[100]szBufferint*

std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));

それreinterpret_castは個人的な好みの問題です。「迫りくる危険、迫りくる危険!」と叫ぶ何かを見たいです。UBの可能性を隠しているが、削除しないCスタイルのキャストに対して未定義の動作を呼び出すことができるものの場合。私(および私のプロジェクトマネージャーの大君主)は、grepを実行できreinterpret_castます。

アライメントの問題のためにこのキャストが有効であるという保証はないため、ここでのUBの可能性は現実的です。

またはstd::copyを介して実装される保証はないことにも注意してください。規格(2003年または2011年)には、を介して、または可能であれば実装する必要があるという言葉は1つもありません。(余談ですが、私が見たすべての実装では、単純な実装が採用されたかのように機能するかどうかを介して実装されます。)memcpymemmovestd::copymemcpymemmovestd::copystd::memmove

std::memcpyここに切り替える唯一の理由std::copyは美学です。美学が邪魔になることもあります。「愚かな一貫性は小さな心のホブゴブリンです。」にこだわるのをお勧めしstd::memcpyます。それはあなたが望むことを正確に行います、そしてこの使用法は重複がなく、バッファが適切なサイズであるため安全です。

于 2012-10-24T11:33:23.803 に答える
1

の標準は、 の動作 (正確な実装ではない場合) が std::copy 以下と同等であるためです。

namespace std { 
  template< typename InIter, typename OutIter >
  OutIter std::copy( InIter begin, InIter end, OutIter outp )
  {
     for( ; begin != end; ++begin, ++outp )
     {
         *outp = *begin;
     }
     return outp;
  }
}

つまり、メンバーごとにコピーし、各反復子をインクリメントして、出力の次の書き込み位置を返します。

これは、ここで実際に必要な memcpy と同じ動作ではありません。memcpy を使用することに何の問題もありません (特定の Microsoft コンパイラが安全でないと言っている場合でも、それは可能ですが、適切に運転しないとトラックを運転することは安全ではありません。だからといって、誰も運転できないわけではありません)。 .

于 2012-10-24T10:52:09.703 に答える
1

ベクトルの内容を生のメモリとして解釈するには、次のように使用reinterpret_castunsigned char *ます。

std::copy(reinterpret_cast<unsigned char *>(&*vData.begin()),
          reinterpret_cast<unsigned char *>(&*vData.end()), szBuffer);

vector::iteratorポインター型であることが保証されていないため、begin 要素と end 要素のアドレスを間接的に取得する必要があります。

これは、 の安全な使用が保証されている数少ない方法の 1 つですreinterpret_cast

于 2012-10-24T11:10:18.283 に答える