2

C++でポインターの動的配列を削除することについて質問があります。次のような状況があると想像してみましょう。

int n;
scanf("%d", &n);
Node **array1 = new Node*[n];
/* ... */

ここで、Nodeは事前に定義された特定の構造です。new演算子で割り当てた後、array1の内容を変更するとします(ただし、何も削除しません!)。配列内でポインターが繰り返される可能性がある場合(線形時間でポインターを並べ替えたりセットに挿入したりせずに)、array1とそのすべてのコンテンツを削除する適切な方法は何ですか?

4

5 に答える 5

3

この割り当ての使用:

Node **array1 = new Node*[n];

array1の内容は未定義です。各要素はでNode*あり、メモリは初期化されていないため、値は何でもかまいません。

ポインタの配列を割り当てても、ポイント先のクラスのオブジェクトは作成されません。

したがって、配列に配置するポインターが何であれ、それらが指すオブジェクトは、他の場所で構築および破棄する必要があります。

だからあなたの質問に答えるために、array1を削除する適切な方法は

delete[] array1;

ただし、これによってデストラクタが呼び出されることはないことに注意してください。配列を削除するNode*に、配列に入れたものをすべて処理する必要があります。

編集:あなたの例で割り当てられた有効な値が 配列にあるかのように、配列の「値を変更する」という元の質問に混乱しました。

しかし...後で削除するためにポインターを追跡したいということを理解したので、おそらく、各ポインターが1回だけ存在する、その目的のために別の配列を作成することができます。したがって、現在上にある配列があります。この配列には、使用している目的に関係なく、繰り返される可能性のあるノードへのポインターが含まれています。次に、削除を管理するという明確な目的のための別の配列があり、各ポインターは1回だけ発生します。nodeCleanupArray[i] = pNewNode直後のようなものを設定するのは簡単なはずです。そうすれば、線形時間と各要素pNewNode = new Node()でその配列を爆破できます。delete(つまり、array1の要素をわざわざ検査する必要はなく、クリーンアップにはnodeCleanupArrayを使用します)

于 2013-03-14T20:13:52.550 に答える
1

この種の問題には多くの解決策がありますが、最も明白な選択はそれを使用するように変更することです

std::vector< std::shared_ptr<Node> >

これで、コードを記述せずに参照カウントポインターが作成され、事前定義されたサイズを知る必要のない「配列」が作成されます。

もちろん、内に参照カウントオブジェクトを実装することNodeも、同じことを行うために独自のコンテナオブジェクトを実装することもできますが、それはほとんどまたはまったくメリットがないという余分な手間がかかるようです。

于 2013-03-14T20:19:50.293 に答える
0

マークアンドスイープを試してください:)管理された環境を実装しようとしています。

次に例を示します。

struct Node
{
... 
    bool marked;

    Node() : marked(false)
    {}
};

ここで削除します:

void do_delete(Node **data, size_t n)
{
    size_t uniq = 0;
    Node **temp = new Node*[n];

    for (size_t i = 0; i < n; i++)
    {
        if (data[i] && !data[i]->marked)
        {
            data[i]->marked = true;
            temp[uniq++] = data[i];
        }
    }

    for (i = 0; i < uniq; ++i)
    {
        delete temp[i];
    } 

    delete[] temp;
    delete[] data;
}
于 2013-03-14T20:12:21.523 に答える
0

これを行う方法は、参照カウンターと、参照カウントが0のときにノード自体を削除するNode :: derefメソッドを使用することです。ノードのリストを反復処理するときに、node->derefを呼び出しても実際には削除されません。配列内の最後のノード参照までオブジェクト。

于 2013-03-14T20:15:40.930 に答える
0

array1とそのすべてのコンテンツを削除する適切な方法は何ですか

単一の割り当てを表示します。new Node*[n]。この割り当てにより、プログラムにを呼び出す責任が与えられますdelete [] whatever_the_return_value_was。これは、その1つの割り当てを削除することだけであり、「そのすべてのコンテンツ」を削除することではありません。プログラムが他の割り当てを実行する場合、プログラムはそれらの責任も処理されるように手配する必要があります。

配列内でポインタが繰り返される可能性がある場合

現在の割り当てに関連付けられていないポインタ値に対する未定義deleteの動作になるため、同じポインタ値を複数回削除することは避けてください。これは、正しい方法が1つしかないという問題ではなく、プログラミングの実践や設計などの問題です。

通常、C ++はRAIIを使用して、手作業でやりたいことをやろうとするのではなく、このようなことを自動的に処理します。これは、手作業で行うのが非常に難しいためです。ここでRAIIを使用する1つの方法は、ノードを「所有する」2番目のオブジェクトを用意することです。次に、生のポインタarray1を「所有していない」ポインタとして使用します。次に、すべてのノードを削除するには、ノードを所有するオブジェクトをスコープ外にするか、破棄します。

{
  // object that handles the ownership of Node objects.
  std::vector<std::unique_ptr<Node>> node_owner;

  // your array1 object that may hold repeated pointer values.
  std::vector<Node*> array1;

  node_owner.emplace_back(new Node); // create new nodes

  array1.push_back(node_owner.back().get()); // put nodes in the array
  array1.push_back(node_owner.back().get()); // with possible duplicates

  // array1 gets destroyed, but it's contents do not, so the repeated pointers don't matter
  // node_owner gets destroyed and destroys all its Nodes. There are no duplicates to cause problems.
}

そして、破壊は線形時間で発生します。

于 2013-03-14T20:31:20.543 に答える