new (pointerT) T()
ループで行います。デストラクタがオブジェクトと呼び出しを破棄するオブジェクトの内部に保持してください(たとえば、それを呼び出します)。コンストラクタでは、次のようにします。pointerT
free
aligned_vector
ptrdiff_t k = 0;
try
{
for (; k < n; k++)
new (pointerT + k) T();
}
catch (...)
{
for (; k > 0; k--) (pointerT + k)->~T();
free(pointerT);
throw;
}
このようにして、構築が失敗した場合でも、トランザクションで救済することができ、メモリやリソースをリークすることはありません。
この目的のために、再利用性の観点から最も簡単なのは、独自のアライメント対応アロケータを実装して使用するstd::vector
ことです。これにより、例外安全性(および他の多くの機能)が処理されます。
コンパイル時のアライメント仕様を備えたサンプルアロケータC++11を次に示します(拡張機能と修正を提案してください)。
template <typename T, size_t align>
struct aligned_allocator
{
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template <typename U>
struct rebind { typedef aligned_allocator<U, align> other; };
T* address(T& t) { return &t; }
T* allocate(size_t n, const T* = 0)
{
if (T* ans = memalign(align, n * sizeof(T))) return ans;
else throw std::bad_alloc();
}
T* deallocate(T* p, size_t) { free(p); }
size_t max_size() const
{
return size_t(-align) / sizeof(T);
}
template <typename U, typename... Args>
void construct(U* p, Args&&... args)
{
::new((void *)p U(std::forward<Args>(args)...);
}
template <typename U>
void destroy(U* p) { p->~U(); }
};
使用例:std::vector<T, aligned_allocator<T, 64>> v(42);
整列されたストレージと64個の要素を使用してベクトルを作成します。
C++11でもできます
template <typename T, size_t align>
using aligned_vector = std::vector<T, aligned_allocator<T, align>>;
そして、あなたは今使うことができます
aligned_vector<MyType, 64> v;
例外安全、移動認識、イテレータ認識、範囲ベースのforループ認識など、整列されたストレージを備えたベクトルをお楽しみください。