一部の開発者は、いくつかの回避策のためにコンストラクタとデストラクタを明示的に呼び出します。それは良い習慣ではありませんが、いくつかのシナリオを実現するために行われているようです。
たとえば、この記事「Beautiful Native Libraries」では、作成者がこの手法を使用しています。
以下のコードでは、最後に、コンストラクターが明示的に呼び出されていることがわかります。
#include <limits>
template <class T>
struct proxy_allocator {
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T& reference;
typedef const T &const_reference;
typedef T value_type;
template <class U>
struct rebind {
typedef proxy_allocator<U> other;
};
proxy_allocator() throw() {}
proxy_allocator(const proxy_allocator &) throw() {}
template <class U>
proxy_allocator(const proxy_allocator<U> &) throw() {}
~proxy_allocator() throw() {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(size_type s, void const * = 0) {
return s ? reinterpret_cast<pointer>(yl_malloc(s * sizeof(T))) : 0;
}
void deallocate(pointer p, size_type) {
yl_free(p);
}
size_type max_size() const throw() {
return std::numeric_limits<size_t>::max() / sizeof(T);
}
void construct(pointer p, const T& val) {
new (reinterpret_cast<void *>(p)) T(val);
}
void destroy(pointer p) {
p->~T();
}
bool operator==(const proxy_allocator<T> &other) const {
return true;
}
bool operator!=(const proxy_allocator<T> &other) const {
return false;
}
};
このようなシナリオでは、コンストラクタとデストラクタを明示的に呼び出す必要がある場合がありますが、標準では、未定義の動作、未指定の動作、実装定義の動作、または明確に定義されているとは何ですか?
はい、サポートされ、明確に定義されています。安全です。
new (reinterpret_cast<void *>(p)) T(val);
配置の新しい構文と呼ばれ、特定のメモリ位置にオブジェクトを構築するために使用されます。これはデフォルトの動作です。投稿されたアロケータで必要なものなど。プレースメントnewが特定のタイプに対してオーバーロードされている場合、T
グローバルプレースメントnewの代わりに呼び出されます。
このような構築されたオブジェクトを破棄する唯一の方法は、デストラクタを明示的に呼び出すこと p->~T();
です。
プレースメントの新規で明示的な破棄を使用するには、実装されたコードがオブジェクトの存続期間を制御する必要があります。この場合、コンパイラはほとんど支援を提供しません。したがって、オブジェクトが適切に配置され、十分に割り当てられた場所に構築されることが重要です。それらの使用は、OPやstd::allocator
。などのアロケータでよく見られます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加