2

ヒープに 2 つのアイテムがあるとします。

Foo *f = new Foo;
Foo *g = new Foo[42];

そして、ポインターを受け取る関数がありFoo、その関数内で次を実行する必要があるとしますdelete

void bar(Foo *p) {
    // some stuff
    delete p;
}

この関数は、次のように呼び出すことができます。

bar(f); // passing a pointer to a Foo object on the heap
bar(g); // passing a pointer to an array on the heap

とで割り当てられたメモリをそれぞれ解放するために と を使用する必要があることdelete[]を認識しています。ただし、関数は、そのパラメーターがまたはで割り当てられているかどうかを認識していないため、どのようにこの関数を適切に機能させることができますか?deletenew[]newpnewnew[]deletedelete[]

4

6 に答える 6

4

単一責任の原則に問題があるようです。

単一のオブジェクトを操作する処理がある程度あるため、個々のオブジェクトまたは配列を渡すのが妥当です。(その処理が、最初のオブジェクト以外の配列要素、または非動的オブジェクトにも役立つのはなぜですか?)

次に、オブジェクトを解放する必要があります。またはアレイ。

ここには3つの異なるタスクがあり、3つの異なる機能が必要です。

基本的に、「関数がそのパラメーターがまたはpで割り当てられたかどうかを知らない」場合、その関数は割り当てを解除しようとするビジネスを持ちません。パラメータがスタックにある場合はどうなりますか?プールされたアロケータが使用された場合はどうなりますか?newnew[]

また、処理を別の関数に移すと、「単一のオブジェクトを処理してから削除する」と「配列を処理してから削除する」の関数を重複することなく簡単に作成できます(どちらも処理コンポーネントのヘルパー関数を呼び出します)。

于 2012-04-21T15:49:24.647 に答える
3

それを(移植可能に)検出して、関数で正しいことを行うことはできません。

「回避策」はstd::vector<Foo>、配列の代わりに使用することであり、常にdelete.

于 2012-04-21T15:42:46.103 に答える
2

解決策 1.コード設計の観点からは、おそらくこのようなケースを完全に回避し、同じクラス、作成と破棄の関数のペア、またはそれを割り当てたコード ブロックによってオブジェクトを削除する必要があります。このように、間違いを犯していないことがわかります。

解決策 2.コンパイラがそれらをサポートしている場合はstd::shared_ptr、ラムダ関数を使用し、必要に応じてポインターごとに異なるデアロケーターを使用します。共有ポインタについては、こちらを参照してください。

std::shared_ptr<Foo> f(new Foo[20], [](Foo* p) { delete[] p; });
std::shared_ptr<Foo> g(new Foo);

最初のものfは、配列への共有ポインターです。作成するとき、最初のパラメーターとして配列への (通常の) ポインターを指定します。2 番目のパラメーターは、パラメーターを受け取るラムダ関数Foo* pあり、その本体は{ delete[] p; }です。

デフォルトでは、メモリの割り当てを解除するためにstd::shared_ptr使用します。deleteこれが、2 番目のものを作成するときに、オブジェクトへのポインターのみを指定し、カスタム デアロケーターを指定しない理由です。

于 2012-04-21T15:56:42.817 に答える
1

できません。ポインタがオブジェクトを指しているのか、そのようなオブジェクトの配列を指しているのかはわかりません。

ただし、割り当て解除のための単一の関数が本当に必要であり、 1つのオブジェクトを割り当てている場合でも、配列のようなものを割り当てることを覚えている場合は、次の使用が合法です。

Foo *h = new Foo[0];
Foo *f = new Foo[1];
Foo *g = new Foo[42];

void bar(Foo *p) {
    // some stuff
    delete [] p;
}

ただし、技術的に可能な場合は、それを使用する必要があるとは限らないことを覚えておいてください。これは、オブジェクトを配列の特殊なケースとして扱うことが理にかなっているかどうかは、ユースケースによって異なります。

より洗練されたC++の方法は、std::vectorまたはboost::scoped_ptrboost::scoped_arrayなどを使用することです。これは、名前が示すように、正しいバージョンのdelete演算子を呼び出すことを保証します。

于 2012-04-21T15:54:00.187 に答える
0

あなたはそれがどれであるかを通過する必要があります。関数は実行時にそれを判断できません。

良い説明については、こちらを参照してください。

于 2012-04-21T15:42:26.883 に答える
-2

これをどのように実装するかを決定するのはコンパイラのベンダー次第であり、そのため「魔法」のカテゴリに分類されます。

一般に、new[] を使用すると、ランタイムは追加の 4 バイトを割り当てます。次に、配列のサイズをこれらのバイトに格納し、割り当て + 4 バイトを返します。割り当てを解除するとき、渡したポインターから 4 を削除し、サイズを読み取り、それを使用して呼び出すデストラクタの数などを決定します。

詳細については、C++ FAQを参照してください。

于 2012-04-21T15:43:08.787 に答える