std::array自体をnewすればヒープ領域に保存されますし、(あまり無いと思いますが)必要であればカスタムアロケータを設定することでstd::vectorの要素をスタック領域に配置できます。
同じ数の要素をメモリ上に展開するのであれば、その分のメモリ領域は消費しますので、「省メモリー」かどうかも設計・実装次第です。std::arrayとstd::vectorの違いにはあたらないと考えます。
std::arrayとstd::vectorの違いは、「必ずN個の要素が生成される」かどうかだと思います。std::arrayでは必ずN個の要素が常に生成され存在する状態になりますし、そのためにN回のコンストラクタが一気に実行されます。なので格納するオブジェクトのコンストラクタで何か処理を行ったり、格納するオブジェクトがリソースを大きく消費する場合、それでいいのかどうかを判断する必要が出てきます。std::vectorはresize()を使えば同じようなことも実現できますし、そうでないようにも制御できます。
繰り返すと、要素数の制御を動的に行う必要があるかどうか、常にN個の要素が必要で増減しないかどうか、が使い分けのポイントではないかと思います。
5/31 コメントでの質問に対する回答
C++では、AがBを直接保持するケースでは、Aの変数が破棄されるとb_も破棄されることが保証されています(b_の破棄についてコードを書く必要はありません)。以下のケースでは、Aが破棄されたのにBが破棄されていないということは言語仕様上ありえません。
C++
1class A
2{
3private:
4 B b_;
5};
newされたBを生ポインタで保持するケースでは、~A()にてb_を破棄する必要があります。これはなぜかというと、Aが管理しているのは、Bの実体ではなく、あくまで(Bの実体への)ポインタだからです。「AはBの実体を管理している」ということはC++文法上では何ら示されておらず、プログラマの頭の中にしかありません。このケースではdelete b_を書き忘れれば、Aが破棄されてもBが破棄されないということはありえます。
C++
1class A
2{
3public:
4 ~A()
5 {
6 delete this->b_;
7 }
8
9 void create_b()
10 {
11 this->b_ = new B();
12 }
13
14private:
15 B* b_;
16};
まともなC++プログラマであれば、生ポインタは使わずスマートポインタを使います。スマートポインタは、そのデストラクタで対象のオブジェクト(この場合Bの実体)のデストラクタを呼んでくれるので、~A()にて後始末のコードを記述する必要はなくなります。
C++
1class A
2{
3public:
4 void create_b()
5 {
6 this->b_ = std::make_shared<B>();
7 }
8
9private:
10 std::shared_ptr<B> b_;
11};
vectorは、保持している要素をきちんと破棄しています(gnuのvectorのソースコードを読むと大変勉強になると思います)。ただし以下のようにした場合は話は別です:
C++
1std::vector<B*> a;
2a.emplace_back(new B());
上記でaが保持しているのはBの実体ではなくポインタです。このようなケースではやはり自前でBの実体を破棄する必要があり、まともな(以下略)
C++
1std::vector<std::shared_ptr<B>> a;
2a.emplace_back(std::make_shared<B>());
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/05/28 01:52
2021/05/28 02:00
2021/05/28 12:16
2021/05/30 22:52
2021/06/01 11:07