C++で配列を動的に取りたい(コンストラクタに引数付きで)


C++で動的に配列を確保し、コンストラクタで初期値を与えようと思っているのですがうまくいかいず困っています  
以下のソースなのですがBaseClassをmain内で動的に配列を確保するまでは出来たのですが  
コンストラクタに引数を追加するとコンパイルエラーになります  
bcRec = new BaseClass(5)[n];やbcRec = new BaseClass(5)[n];  
と言った風にしてみたのですが・・・  
正しい文法はどのように記述したら良いのでしょう

**BaseClass.h**

[code]

    class BaseClass{
    private:
        int _a;
    public :
        BaseClass();
        BaseClass(int a);
        void setint(int a);
        int fooint();
    };
    
[/code]

**BaseClass.cpp**

[code]

    #include "BaseClass.h"
    BaseClass::BaseClass(int a){
        _a = a;
    }
    
    void BaseClass::setint(int a){
        _a = a;
    }
    
    BaseClass::BaseClass(){
        _a = 0;
    }
    
    int BaseClass::fooint(){
        return _a;
    }
    
[/code]

**main.cpp**

[code]

    int main(){
        BaseClass bc(10);
        BaseClass *bcRec;
        int n;
    
        n = 10;
        bcRec = new BaseClass[n]; //★本当は引数付きのコンストラクタを使いたい
    
        for (int i = 0; i < n; i++) {
            bcRec[i].setint(i * 10);
            std::cout << bcRec[i].fooint() << "\r\n";
        }
    }
    
[/code]




前提条件があるので、いつでも使えるというわけではありませんが、動的な配列はC++では、`std::vector`が第一候補です。

[code]

    #include <iostream>
    #include <vector>
    #include "BaseClass.h"
    
    int main() {
        int n;
    
        n = 10;
        std::vector<BaseClass> bcRec; // 空のvectorを再生
        bcRec.reserve(n);             // n個分のメモリを確保するが初期化はしない
    
        // vectorの最後に、初期化をしながら(コンストラクタを呼びながら)
        // 一つずつBaseClassを追加
        for (int i = 0; i < n; ++i) {
            bcRec.emplace_back(i * 10);
        }
    
        // 中身を確認
        for (int i = 0; i < n; i++) {
            std::cout << bcRec[i].fooint() << '\n';
        }
    
        return 0;
    }
    
[/code]




`new`は次の２つの役割を持っています。

  * メモリ確保を行う
  * コンストラクターを呼び出す 
    * （非配列版）引数を指定できる
    * （配列版）引数を指定できず、デフォルトコンストラクターが呼ばれる

この質問では、配列版においてデフォルトコンストラクター以外を呼び出したい、とのことですが、とりあえずは実現できません。

ただし、[`new`](https://ja.cppreference.com/w/cpp/memory/new/operator_new)の機能を分割して、それぞれを呼び出せば実現可能です。  
`::operator new`は指定されたサイズのメモリを確保し、対になる`::operator delete`で解放できます。またplacement
new（配置new）は指定されたアドレス上でコンストラクターを実行します。

[code]

    // メモリ確保
    bcRec = static_cast<BaseClass*>(::operator new(sizeof(BaseClass) * n));
    // コンストラクター実行
    for (int i = 0; i < n; i++)
        ::new (bcRec + i)BaseClass(5);
    // デストラクター実行
    for (int i = 0; i < n; i++)
        bcRec[i].~BaseClass();
    // メモリ解放
    ::operator delete(bcRec);
    
[/code]

STLはこれを支援する関数を提供しています。

[code]

    std::allocator<BaseClass> al;
    // メモリ確保
    bcRec = al.allocate(n);
    // コンストラクター実行
    std::uninitialized_fill_n(bcRec, n, 5);
    // デストラクター実行
    std::destroy_n(bcRec, n);
    // メモリ解放
    al.deallocate(bcRec, n);
    
[/code]

とはいえ、上記コードは煩雑であり、要素数を誤ると簡単に不正な処理を行ってしまうため非常に危険です。STLに用意されている[`std::vector`](https://ja.cppreference.com/w/cpp/container/vector)で動的に確保することをお勧めします。特に`reserve()`で事前にメモリ確保しておくことで、要素数増減に伴うメモリ確保のオーバーヘッドを削減することができます。

