5

スマート ポインターの 2 次元配列を動的に割り当てる必要がありますが、その構文がわかりにくいです。これを動的にする必要があります:

std::unique_ptr<someClass> myArray[size1][size2];

したがって、私が理解していることから、型へのポインターへのポインターを作成します。

someClass** myArray; //actaully the type is std::unique_ptr<someClass> but I'll just keep it simple

それを割り当てるには、次のようにします。

myArray* = new someClass*[size1];
for(int i = 0; i < size1; i++)
    myArray[i] = new someClass[size2];

しかし、これはスマート ポインターを使用しないため、後で手動で削除する必要があり、これらのポインターをスマート ポインターにする方法がわかりません。

タイプは std::unique_ptr ですが、タイプへのポインターへのポインターが必要なので、試しました:

std::unique_ptr<std::unique_ptr<std::unique_ptr<someClass>>> myArray;

しかし、この後、私はそれをどのように割り当てるかについて迷っています。誰か助けてくれませんか?

4

2 に答える 2

6

問題を具体的に解決する方法と、このような問題に一般的にアプローチする方法を紹介します。

一般に、複雑になりすぎる問題と同じように、それを分解してみてください。C および C++ で複雑な型宣言を分解するためのツールは、長い間 "typedef" でした。あなたが持っているもののようなカスケード型定義にアプローチする方法は次のとおりです。最も内側のラッピングタイプ、つまりクラスをラッピングするunique_ptrを取り、ラップしたいタイプのtypedefを作成します。次に、最も外側の型になるまで、その型がラップされている型に対して同じことを続けます。

これはあなたの質問にのみ関連していますが、後でテンプレートで現在抱えているような同様の問題に遭遇する可能性があるため、言及したいと思います。C++11 以降、"using" 句を使用して、テンプレート パラメーターを含む型のエイリアスをより便利に定義することもできます: http://en.cppreference.com/w/cpp/language/type_alias。このコンテキストで興味がある場合、または将来的に関連する場合は、そのリンクをチェックしてください!

あなたの特定の問題に。関数 "test_dynamic_2darray1" は、スマート ポインターの 2 次元 10x10 配列を構築します。このコードを実行すると、マネージ配列が範囲外になったときに、デストラクタから 100 行の出力が表示されます。

size_t destructor_count = 0;
class MyClass {
    public:
    ~MyClass() {
        std::cout << "Destructor call #" << ++destructor_count << std::endl;
    }
};

typedef std::unique_ptr<MyClass[]> ManagedC;

void test_dynamic_2darray1() {
    size_t dimension1 = 10, dimension2 = 10;

    auto managed_array = std::unique_ptr<ManagedC[]>(new ManagedC[dimension1]);
    for (size_t i = 0; i < dimension1; ++i)
        managed_array[i] = ManagedC(new MyClass[dimension2]);
}

動的に割り当てられたクラス インスタンスのデストラクタが呼び出されず、出力が表示されないこのコードと比較してください。

void test_dynamic_2darray2() {
    size_t dimension1 = 10, dimension2 = 10;

    auto simple_array = new MyClass*[dimension1];
    for (size_t i = 0; i < dimension1; ++i)
        simple_array[i] = new MyClass[dimension2];
}

私はあなたの質問に答えることができたことを願っています! :) 何か詳しく説明してほしい場合はお知らせください。先日、関連するブログ投稿も書きまし。多次元動的配列へのさまざまなアプローチを示し、ベクトルのベクトルを使用する頻繁に提案される方法のパフォーマンスを調べるため、ここに投稿します。

最後になりましたが、配列を反復処理するための int の使用について言及させてください。これが私の面倒なことにならないことを願っていますが、これがたくさん行われているのを見ています. おそらくsize_tを使用する必要があります。なんで?たとえば、私の 64 ビット マシンでは "int" は 32 ビットですが、size_t で表されるアドレスは 64 ビットです。この int の誤用は、特に 32 ビット アプリケーションを 64 ビット マシンに移植する際に、多くのバグの原因となっています。配列アドレス間のオフセットなどの用途で符号付き型が必要な場合は、おそらく ptrdiff_t を使用することをお勧めします。

于 2015-01-16T22:14:11.630 に答える
4

説明に役立つ例として、スマート ポインター ( ) およびやunique_ptrなどのその他の機能を使用して (サイズが 3 x 5 の) 2D int 配列を作成および入力するために C++ 現代で使用できる構文を以下に示します。make_uniquemove()

unique_ptr<unique_ptr<int[]>[]>     smartPtr2D;
unique_ptr<int[]>                   smartPtr1D;

int dataCounter = 0;

smartPtr2D = make_unique< unique_ptr<int[]>[] >(3);
for (int i = 0; i<3; i++)
{
    smartPtr1D = make_unique<int[]>(5);
    for (int j = 0; j<5; j++)
    {
        smartPtr1D[j] = dataCounter;
        dataCounter++;
    }
    smartPtr2D[i] = move(smartPtr1D);
}
于 2016-12-16T05:51:55.067 に答える