1

教育目的でコンテナVectorを実装しようとしています。メソッドリザーブ
を 実装しているときに、私は質問に直面しました。それは、要素の配列をメモリ内の1つの場所(初期容量)から新しい容量に割り当てられたメモリに再配置するための最良の方法ですか? ループを使用するか、c関数memcpyを使用するかの2つの可能性を検討します。 これが私の実装です:


template <typename T>
void MyVector<T>::reserve(int elements) 
{
    if (m_size >= elements) // when no need to reserve memory as at least demanded amount of memory has been already allocated
        return;
    m_capacity = elements;
    tmp = m_array;
    // allocate needed amout of memory:
    m_array = new T[elements];
    // copy elements ???? can I use memcpy????
    for (int i = 0; i < m_size; ++i)
    {
        m_array[i] = tmp[i];
    }
    delete tmp;
}

template <typename T>
void MyVector<T>::reserve1(int elements) 
{
    if (m_size >= elements) // when no need to reserve memory as at least demanded amount of memory has been already allocated
        return;
    m_capacity = elements;
    tmp = m_array;
    // allocate needed amout of memory:
    m_array = new T[elements];
    // copy elements ???? can I use memcpy????
    memcpy(m_array, tmp, m_size);
    delete [] tmp;
}

質問: -どのボトルネックを考慮に入れる必要がありますか?
-パフォーマンスにはどのような違いがありますか?
-より効率的な方法はありますか?
-STLコンテナの実装が詳細に説明されている情報源にアドバイスをいただけますか(私の目的は、自分で実装を作成し、専門的な実装と比較して、知識を確認し、改善が必要な領域を見つけることです)

4

3 に答える 3

5

memcpy重要なオブジェクトには他のメモリブロックへのポインタが含まれている可能性があるため、使用できません。

次のベクトルについて考えてみstd::stringます。それぞれは通常、動的に割り当てられた文字の配列へのポインタを含む小さなオブジェクトとして実装されます。文字列の場合memcpy、ポインタのコピーを作成しますが、実際の文字データのコピーは作成しません。ただし、これらのポインターの所有権は譲渡されません。したがって、元の配列(これらすべての文字列のデストラクタを呼び出す)を削除すると、それらのメモリが解放され、「新しい」オブジェクトにはすべてダングリングポインタがあります。

を使用するstd::copyことは、これを達成するためのより良い方法です。

于 2013-03-21T21:54:57.663 に答える
1

memcpyパフォーマンスの側面だけでなく、「単純なループ」メソッドを使用してオブジェクトをコピーすることで違いが生じる他の要因もあります。例えば:

class Blah
{
    Blah()
    {
        some_function(this);
    }
};

MyVector<Blah> v;

... 

これで、[何らかの理由で]何らかの方法でsome_function保存すると、削除されますが、への参照は削除されたオブジェクトを指したままになります。これはおそらくあなたが望んでいたものではありません。thisreserve1this

もちろん、オブジェクトに内部で割り当てを使用するオブジェクトが含まれている場合も同じです。たとえば、std::string

于 2013-03-21T21:56:58.553 に答える
0

私はロディに同意します。しかし、さらに悪いことに。デストラクタを呼び出さずに古いメモリを解放し、他のメモリが解放されない場合でも、一部のオブジェクトには内部パーツへの参照またはポインタが含まれている可能性があり、とにかく壊れます。最後に、新しいメモリアライメントの結果を知っておくとよいでしょう(T = charの場合、memcpyがおそらく最良です)。

それが機能する場合は、ムーブ代入を強制するforことが最善の解決策になる可能性があります。(古いコピーは必要ありません)

さて、最終的には、std :: vectorがどのように設計されているかを確認できます。個別のメモリ割り当てがあり、初期化されていない状態で、初期化、コピー、または移動されます。StroustrupによるC++プログラミング言語第3版の19.4アロケータをご覧ください。

于 2013-03-21T22:11:18.857 に答える