2017-07-05 5 views
1

STLコンテナ自体がコピーされたり移動されたときに通知する簡単な方法があるかどうかは疑問でした。STLメソッドを変更したりオーバーロードしようとすることの複雑さに対処する必要はありません。STLの移動およびコピーコンストラクタの通知を受ける従来の方法はありますか?

シングルスレッドアプリケーションをデバッグしているときに、単純なstd::coutの出力を使用して移動およびコピーを通知します(独自の参照型が意図したとおりに動作することを確認してください)。

私はしばらくそれを考えていましたが、実際には本当に馬鹿馬鹿しいアイデア(std :: moveのように実際のコードを生成して移動候補を作成しようとしていることを通知します)笑)。または、実際のSTLの移動とコピーコンストラクタをオーバーロードし、実際のSTLを呼び出すことができますか?

これは、物事が実際に移動されている場所(つまり、型がconstの場合はコピー操作に崩壊しない)を正確にコピーしている場所を知るのに便利だと考えています。

すべての洞察は興味深く、高く評価されます。

+4

本当にひどい考えです。可能なプロファイリングツールと静的解析ツールを代わりに使用します。 –

+0

私の頭の上からのベストアイデアはカスタムアロケータですが、それは追跡するすべてのインスタンスの宣言ポイントを制御する場合にのみ機能します。 – HeroicKatora

+3

もう1つの注意: 'namespace std'(' std :: move'などの実装を含む)内にあるものを宣言すると、未定義の動作になります。 – HeroicKatora

答えて

4

いいえ良い方法はありません。 HeroicKatora's commentは、私が知っている唯一の可能性です:メッセージがコピー構築され、構築されたときにメッセージを出力するカスタムアロケータを構築します。しかし、問題があります...

カスタムアロケータをビルドするには、私のallocator boilerplate(著作権、参照、またはリンクは必要ありません)を使用して自由に感じてください。これは単なるスケルトンアロケータです。特別なものは何もない。私はこの質問に対して次のストローマンアロケータを作成するために、これを使用しました

template <class T> 
class allocator 
{ 
public: 
    using value_type = T; 

    allocator() = default; 
    allocator(allocator const&) = default; 
    allocator(allocator&&) 
    { 
     std::cout << "container move construction\n"; 
    } 

    template <class U> allocator(allocator<U> const&) noexcept {} 

    value_type* // Use pointer if pointer is not a value_type* 
    allocate(std::size_t n) 
    { 
     return static_cast<value_type*>(::operator new (n*sizeof(value_type))); 
    } 

    void 
    deallocate(value_type* p, std::size_t) noexcept // Use pointer if pointer is not a value_type* 
    { 
     ::operator delete(p); 
    } 

    allocator 
    select_on_container_copy_construction() const 
    { 
     std::cout << "container copy construction\n"; 
     return *this; 
    } 
}; 

template <class T, class U> 
bool 
operator==(allocator<T> const&, allocator<U> const&) noexcept 
{ 
    return true; 
} 

template <class T, class U> 
bool 
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept 
{ 
    return !(x == y); 
} 

コンテナコピー構造、コピー構築コンテナのアロケータを取得するためにstd::allocator_traits<your_allocator>::select_on_container_copy_construction()を呼び出すために必要とされます。アロケータでこの関数を実装しないと、std::allocator_traitsはアロケータのコピーを返します。私はこのデフォルトの動作をオーバーライドしてメッセージを出力しました。

コンテナを移動するときは、アロケータを構築する必要があります。そこで、allocator移動コンストラクタを変更してメッセージを出力しました。

問題この方法では、コンテナがアロケータを1回だけ移動またはコピーする必要はありません。

template <class T> using vector = std::vector<T, allocator<T>>; 
template <class T> using deque = std::deque<T, allocator<T>>; 

int 
main() 
{ 
    vector<int> v; 
    std::cout << "Begin move\n"; 
    auto v2 = std::move(v); 
    std::cout << "End move\n"; 
    std::cout << "Begin copy\n"; 
    auto v3 = v2; 
    std::cout << "End copy\n"; 
} 

GCC出力:

Begin move 
container move construction 
End move 
Begin copy 
container copy construction 
End copy 

Visual Studioがコピーに無償移動構成を追加します

GCCは、このドライバのための理想的な結果を提供し、例えば、容器としてvectorを使用

Begin move 
container move construction 
End move 
Begin copy 
container copy construction 
container move construction 
End copy 

LLVMのlibC++は、移動の構成を2倍にします。要約すると、不満足な「並べ替え」である。 : - \

+0

VC++とlibC++に対してバグレポートを提出する必要がありますか? – TemplateRex

+0

これらのプラットフォームでこの動作を変更することに興味がある場合は、はい。これはQOIの問題であり、適合性の問題ではないことに留意してください。 –

関連する問題