1 に答える
人生を楽にする方法は何も知りません。すべての定型コードを提供することで、アロケーターの作成がallocator_traits
本当に簡単になりますが、アロケーターの使用には役立ちません。
GCC 4.7に追加した C++03 と C++11 の両方のコードで単一のアロケーター API を使用できるよう<ext/alloc_traits.h>
に、クラス テンプレートは、C++11 モードで__gnu_cxx::__alloc_traits
使用し、関連するメンバー関数を直接呼び出す一貫した API を提供します。 allocator_traits
C++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));
これにより、生活が少し楽になります。