1 に答える
人生を楽にする方法は何も知りません。すべての定型コードを提供することで、アロケーターの作成がallocator_traits 本当に簡単になりますが、アロケーターの使用には役立ちません。
GCC 4.7に追加した C++03 と C++11 の両方のコードで単一のアロケーター API を使用できるよう<ext/alloc_traits.h>に、クラス テンプレートは、C++11 モードで__gnu_cxx::__alloc_traits使用し、関連するメンバー関数を直接呼び出す一貫した API を提供します。 allocator_traitsC++03 モードのアロケータ。
いいえ、ラッパーやショートカットはありません。C++11 アロケーターの要件により、コンテナー作成者の仕事ははるかに複雑になります。要件は、メモリの管理方法に応じて、コンテナーごとにわずかに異なります。ベクトルのような型の場合、コピー代入演算子で
propagate_on_container_copy_assignment(POCCA) が false で、既存の容量がソース オブジェクトのサイズよりも大きい場合、既存のメモリを再利用できます (POCCA が true で、新しいアロケータがそうでない場合)。アロケーターが置き換えられた後、後で割り当てを解除することができないため、古いメモリを再利用することはできません) しかし、その最適化は、リストやマップなどのノードベースのコンテナーにはあまり役立ちません。おそらく置き換えたいと思いますが、それはほとんど正しいように見えます
return ::new(&sp->m_obj) T(std::move(obj));と
A a(m_alloc); std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj)); return &sp->m_obj;
[container.requirements.general]/3 で述べたように、アロケーターを使用allocator_traits<A>::constructして要素の型T自体を作成するコンテナーですが、割り当てられた他の型 ( your などstorage) を使用してはなりませんconstruct。
それstorage自体が構築されているstorage::m_obj場合、そのメンバーが、std::aligned_storage<sizeof(T)>後で明示的に初期化できる など、初期化されていないままにしておくことができる型でない限り、構築されallocator_traits<A>::constructます。または、重要な構成が必要な各メンバーを個別に構成します。たとえば、メンバーstorageも持っている場合string:
storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1);
sp->m_special_data = 69105;
::new (&sp->m_str) std::string("foobar");
A a(m_alloc);
std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj));
return &sp->m_obj;
メンバーは自明な型であるため、m_special_dataストレージが割り当てられるとすぐにその有効期間が始まります。m_strとのm_objメンバーは重要な初期化を必要とするため、それらのライフタイムはコンストラクターが完了すると開始されます。これは、配置 new とconstruct呼び出しによってそれぞれ行われます。
編集:最近、標準に欠陥があり(私が報告しました)、呼び出しconstructでリバウンドアロケーターを使用する必要がないことを知りました。したがって、これらの行は次のとおりです。
A a(m_alloc);
std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj));
次のように置き換えることができます:
std::allocator_traits<storage_alloc>::construct(m_alloc, &sp->m_obj, std::move(obj));
これにより、生活が少し楽になります。