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());

としてひとつ一時オブジェクトを作りそれをコピーしているから。
だからもしコンテナ製作者で余計なオブジェクトを作りたくないなら、代わりに

template
void 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());

置き換えてやる。