web-dev-qa-db-ja.com

std :: moveの後にデストラクタ呼び出しが必要なのはなぜですか?

C++プログラミング言語Edition 4には、ベクトル実装の例があります。メッセージの最後にある関連コードを参照してください。

uninitialized_move()は、新しいTオブジェクトを古いメモリ領域から移動して、新しいメモリ領域に初期化します。次に、元のTオブジェクトである移動元オブジェクトのデストラクタを呼び出します。この場合、デストラクタ呼び出しが必要なのはなぜですか?

これが私の不完全な理解です。オブジェクトの移動とは、移動元オブジェクトが所有するリソースの所有権が移動先オブジェクトに転送されることを意味します。移動元オブジェクトの残りは、破棄する必要のない組み込み型の一部の可能なメンバーです。vector_basebがスコープ外になると、割り当てが解除されます(の内側()swap()呼び出しの後)。 moved-fromオブジェクトのすべてのポインタをnullptrに置くか、何らかのメカニズムを使用してそれらのリソースのmoved-fromオブジェクトの所有権を削除し、安全を確保します。そのため、「vector_base b "デストラクタは、スワップが完了した後にメモリを割り当て解除しますか?

デストラクタを呼び出す必要がある場合にデストラクタを明示的に呼び出す必要があることは理解しています(たとえば、要素を削除する)ため、デストラクタを呼び出す必要がありますが、std :: move + vector_baseの割り当て解除後にその意味を確認できません。ネットでいくつかのテキストを読んだところ、moved-fromオブジェクトのデストラクタ呼び出しが、オブジェクトの存続期間が終了したことを示す信号(だれに、または何に)として表示されています。

デストラクタが行う意味のある作業が残っていることを教えてください。ありがとうございました!

以下のコードスニペットはここからです http://www.stroustrup.com/4th_printing3.html

template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=capacity()) return;                   // never decrease allocation
    vector_base<T,A> b {vb.alloc,size(),newalloc-size()};   // get new space
    uninitialized_move(vb.elem,vb.elem+size(),b.elem);  // move elements
    swap(vb,b);                                 // install new base 
} // implicitly release old space

template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
    using T = Value_type<Out>;      // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_)
    for (; b!=e; ++b,++oo) {
        new(static_cast<void*>(&*oo)) T{move(*b)};  // move construct
        b->~T();                                // destroy
    }
    return oo;       
}
24
cvomake

オブジェクトからの移動とは、移動されたオブジェクトmightがそのガットを寄付して、[おそらく]になる直前に別のライブオブジェクトに住むことを意味します死ぬ。ただし、オブジェクトが根拠を提供したからといって、オブジェクトは死んでいないことに注意してください。実際、それは別の寄付オブジェクトによって復活し、そのオブジェクトの内臓に住んでいる可能性があります。

また、移動構築または移動割り当ては実際にはコピーである可能性があることを理解することが重要です!実際、移動される型がたまたまコピーコンストラクターまたはコピー割り当てを持つC++ 11以前の型である場合、それらはコピーになります。クラスにmoveコンストラクターまたはmove割り当てがある場合でも、たとえばアロケーターが一致しないため、ガットを新しいオブジェクトに移動できないように選択する場合があります。

いずれの場合でも、移動されたオブジェクトにはまだリソースがあるか、統計などを記録する必要があります。オブジェクトを取り除くには、オブジェクトを破棄する必要があります。クラスのコントラクトによっては、移動後の状態が定義されている場合があり、それ以上の手間をかけずに新しい用途に使用できます。

34
Dietmar Kühl