C++編で扱っている C++ は 2003年に登場した C++03 という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14 -> C++17 -> C++20 -> C++23 と更新されています。
なかでも C++11 での更新は非常に大きなものであり、これから C++ の学習を始めるのなら、C++11 よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。
問題① std::vector のコンストラクタの実装例を挙げました。これを踏まえると、デストラクタはどうなっていると考えられますか? アロケータと関係がないことについては気にしなくて良いです。
外部から指定されたアロケータか、デフォルトのアロケータを使って、オブジェクトの解体と、メモリ領域の解放を行っています。順番に注意してください。
template <typename T, typename Allocator = allocator<T> >
class vector {
public:
typedef std::size_t size_type;
* elems;
T;
Allocator allocator
~vector()
{
if (empty()) {
return;
}
// オブジェクトを解体する
for (size_type i = 0; i < size(); ++i) {
.destroy(&elems[i]);
allocator}
// メモリ領域を解放する
.deallocate(elems, 1);
allocator}
};
問題② std::list で独自のアロケータを使い、rebind のメカニズムが機能していることを確認してください。
たとえば、int型を確保するアロケータを用意して、直接、メモリ確保などの操作を行った場合と、std::list に同じアロケータを渡した場合の違いを確認します。typeid(【言語解説】第31章)を使って、アロケータの各種メンバ関数で、型名を出力するようにしてみます。
#include <iostream>
#include <limits>
#include <list>
#include <typeinfo>
template <typename T>
class MyAllocator {
public:
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 <typename U>
struct rebind {
typedef MyAllocator<U> other;
};
() throw() {}
MyAllocator(const MyAllocator& rhs) throw() {}
MyAllocatortemplate <typename U> MyAllocator(const MyAllocator<U>& rhs) throw() {}
~MyAllocator() throw() {}
(size_type num, std::allocator<void>::const_pointer hint = 0)
pointer allocate{
std::cout << "allocate: " << typeid(T).name() << std::endl;
const std::size_t size = num * sizeof(T);
return static_cast<pointer>(::operator new(size));
}
void deallocate(pointer p, size_type num)
{
std::cout << "deallocate: " << typeid(T).name() << std::endl;
::operator delete(p);
}
void construct(pointer p, const T& value)
{
new((void*)p) T(value);
}
void destroy(pointer p)
{
((T*)p)->~T();
}
(reference value) const { return &value; }
pointer address(const_reference value) const { return &value; }
const_pointer address
size_type max_size() const throw()
{
return std::numeric_limits<size_t>::max() / sizeof(T);
}
};
template <>
class MyAllocator<void> {
public:
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
template <typename U>
struct rebind {
typedef MyAllocator<U> other;
};
};
template <typename T1, typename T2>
bool operator==(const MyAllocator<T1>&, const MyAllocator<T2>&) throw()
{
return true;
}
template <typename T1, typename T2>
bool operator!=(const MyAllocator<T1>&, const MyAllocator<T2>&) throw()
{
return false;
}
int main()
{
typedef MyAllocator<int> IntAllocator;
typedef std::list<int, IntAllocator> IntAllocatorList;
;
IntAllocator myAllocator
int* p = myAllocator.allocate(1);
.construct(p, 0);
myAllocator.destroy(p);
myAllocator.deallocate(p, 1);
myAllocator
(myAllocator);
IntAllocatorList lst.push_back(0);
lst}
実行結果(Visual Studio 2017):
allocate: int
deallocate: int
allocate: struct std::_List_node<int,void * __ptr64>
allocate: struct std::_Container_proxy
allocate: struct std::_List_node<int,void * __ptr64>
deallocate: struct std::_List_node<int,void * __ptr64>
deallocate: struct std::_List_node<int,void * __ptr64>
deallocate: struct std::_Container_proxy
実行結果(clang 5.0.0):
allocate: i
deallocate: i
allocate: NSt3__111__list_nodeIiPvEE
deallocate: NSt3__111__list_nodeIiPvEE
std::list の場合には、複雑な型名が出力されていますが、よく見ると「list node」のような名前が見えます。これが、内部的に持っている、管理用の構造体の型だと推察できます(実際にソースコードを確認すれば見つかります)。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
![]() |
管理者情報 | プライバシーポリシー |