allocator考察
標準コンテナは初期値を持たないコンストラクタはどうしてるかというお話。たとえばstd::vectorでいえばvector()やvector(size)なんか。そのとき内部型をTとすると、T()を呼び出す。ということはintやdoubleなんかも必ず0になる。しかしおもしろいことがひとつあって以下のコードを実行すると
#include#include class test_obj{ private: int c; public: test_obj(){ std::cout<< "constructor!" << c <<"\n"; } test_obj(const test_obj& r):c(r.c){ std::cout<< "constructor!" << c <<"\n"; } ~test_obj(){ std::cout<< "destructor!" << c <<"\n"; } }; int main(){ typedef std::vector V; V v(3); }
結果は
constructor!2293728 constructor!2293728 constructor!2293728 constructor!2293728 destructor!2293728 destructor!2293728 destructor!2293728 destructor!2293728
となってコンストラクタとデストラクタが4つずつになる。上の例ではvector(3)として、3つ確保するようにしているのにだ。なぜか?
それはvector内部で
std::uninitialized_fill_n(begin(),size(),test_obj());
としてひとつ一時オブジェクトを作りそれをコピーしているから。
だからもしコンテナ製作者で余計なオブジェクトを作りたくないなら、代わりに
templatevoid uninitialized_initialize_n(In first, size_t n){ typedef typename std::iterator_traits ::value_type V; while(n--){ new (static_cast (&*first)) V(); ++first;} }
な配置構文newを使った関数を作って
uninitialized_initialize_n(begin(),size());
置き換えてやる。