web-dev-qa-db-ja.com

動的配列の初期化リスト?

静的配列の定義に初期化子リストを与えることができます。例:

int main()
{
  int int_static[2] = {1,2};
}

同様の初期化子リストは動的配列で可能ですか?

int main()
{
  int* int_ptr = new int[2];
}

これは私がやろうとしていることに近いです:

struct foo
{
  foo(){}
  foo(void * ptr): ptr_(ptr) {}
  void * ptr_;
};

int main()
{
  foo* foo_ptr = new foo[10];
}

初期化時には、デフォルトのコンストラクターではなく、foo:foo(void *)を呼び出す必要があります。

動的配列の静的初期化子リストを持つことのポイントは、使用可能なスタックの量が限られているアクセラレータコアのジャストインタイムコンパイルの場合に役立つ可能性がありますが、同時にオブジェクトを構築します。 (アクセラレータのコンパイル時間=ホストの実行時間)静的初期化子リスト。

私はそうではないと思います(これには、コンパイラが追加のコードを生成する必要があるため、つまり、引数の値をヒープの場所にコピーする必要があるため)。 c ++ 0xはこれの一部をサポートしていると思いますが、使用できません。今、私はそのような構成を使用することができました。多分誰かがトリックを知っています。

ベスト!

12
ritter

いいえ、それはできません。

このようなことを許可しても言語にNice-to-have機能が追加されないため、C++ではこれが許可されていないと思います。言い換えると、static初期化子を使用して配列を初期化する場合、dynamic配列のポイントは何でしょうか?

動的配列のポイントは、実際のニーズに応じて、実行時に既知であるサイズNの配列を作成することです。つまり、コード

int *p = new int[2]; 

以下よりも私には意味がありません:

int *p = new int[N]; //N is known at runtime

もしそうなら、Nは実行時までわからないので、static初期化子の要素数をどのように提供できますか?

あなたがこれを書くことを許可されていると仮定しましょう:

int *p = new int[2] {10,20}; //pretend this!

しかし、これを書くことでどのような大きな利点が得られますか?何もありません。そのほぼと同じ:

int a[] = {10,20};

本当の利点は、N要素の配列に対してそれを記述できる場合です。しかし、問題はこれです:

 int *p = new int[N] {10,20, ... /*Oops, no idea how far we can go? N is not known!*/ };
11
Nawaz

OPがこの質問を投稿した時点では、C++ 11のサポートはまだあまり普及していない可能性があります。そのため、受け入れられた回答では、これは不可能であると述べています。ただし、明示的な初期化子リストを使用した動的配列の初期化は、すべての主要なC++コンパイラでサポートされるようになりました。

構文_new int[3] {1, 2, 3}_はC++ 11で標準化されました。 cppreference.comの新しい式ページを引用します。

New-expressionによって作成されたオブジェクトは、次のルールに従って初期化されます。
.。
 タイプ は配列型で、オブジェクトの配列が初期化されます。
.。
 イニシャライザ は中括弧で囲まれた引数のリストであり、配列は集計で初期化されます。 (C++ 11以降)

したがって、OPの例を考えると、C++ 11以降を使用する場合、以下は完全に合法です。

_foo * foo_array = new foo[2] { nullptr, nullptr };
_

初期化子リストにポインターを指定することにより、実際にはコンパイラーを誘導して、(デフォルトのコンストラクターではなく)foo(void * ptr)コンストラクターを適用します。これは望ましい動作でした。

15
DaoWen

いいえ、要素を動的に作成する必要があります。

または、ローカル配列を使用して、その要素を動的に割り当てられた配列の要素にコピーすることもできます。

int main() {
   int _detail[] = { 1, 2 };
   int * ptr = new int[2];
   std::copy( _detail, _detail+(sizeof detail / sizeof *detail), ptr );
   delete [] ptr;
}

すべての要素を0に設定する限定バージョンでは、new呼び出しで追加の括弧のペアを使用できます。

int * ptr = new int[2]();  // will value initialize all elements

しかし、あなたは別のものを探しているようです。

あなたが実際のクラスであるとすると、intよりも複雑であり、異なる値から構築されているため、複雑です。デフォルトの正しい値を持つ既存の配列/ベクトルがある場合、または新しい配置を使用する必要がある場合は、イテレータを使用してベクトルを作成できます。

//vector
int main()
{
  int int_static[2] = {1,2};
  std::vector<int> int_dynamic(int_static, int_static+2);
  //this is what everyone else is saying.  For good reason.
}
//placement new
int function_that_returns_constructed_from_values() {
    return Rand();
}
int main() 
{
    int count = 2;
    char *char_dynamic = new char[count * sizeof(int)];
    int *int_dynamic = char_dynamic;
    for(int i=0; i<count; ++i)
        new(int_dynamic+i)int(function_that_returns_constructed_from_values());
    //stuff
    for(int i=0; i<count; ++i)
        (int_dynamic+i)->~int(); //obviously not really int
    delete []char_dynamic;
}

明らかに、これを行うにはベクトルが好ましい方法です。

0
Mooing Duck

イニシャライザデータはとにかくどこかにある必要があります。単に名前を付けてください。

例えば。、

#include <stddef.h>
#include <algorithm>        // std::copy
#include <vector>

typedef ptrdiff_t   Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }

int main()
{
    using namespace std;

    static int const    initData[]  = {1,2};
    static Size const   n           = countOf( initData );

    // Initialization of a dynamically allocated array:
    int*        pArray  = new int[n];
    copy( initData, initData + n, pArray );

    // Initialization of a vector:
    vector<int> v( initData, initData + n );
}

[〜#〜] edit [〜#〜]:上記のコードのthinkoを修正しました。リクエストに応じて急いで例を追加しました。したがって、私が置いたものは、std::copyからの戻り値を誤って使用していました。

乾杯&hth。、