38

これは、しばらくの間私を悩ませてきた質問です。deleteC ++は、演算子(角かっこなし)が演算子でも機能するように設計されているべきだといつも思っていましたnew[]

私の意見では、これを書く:

int* p = new int;

1つの要素の配列を割り当てることと同等である必要があります。

int* p = new int[1];

これが当てはまる場合、delete演算子は常に配列を削除している可能性があり、演算子は必要ありませんdelete[]

delete[]演算子がC++で導入された理由はありますか?私が考えることができる唯一の理由は、配列の割り当てはメモリフットプリントが小さいため(配列サイズをどこかに保存する必要がある)、deletevsを区別することdelete[]はメモリの最適化が小さいことです。

4

7 に答える 7

43

個々の要素のデストラクタが呼び出されるようにするためです。はい、POD の配列の場合、大きな違いはありませんが、C++ では、自明でないデストラクタを持つオブジェクトの配列を持つことができます。

さて、あなたの質問は、andのように動作させてnewandを削除してみませんか? Stroustrup の "Design and Evolution" の本に戻って、C++ の機能を使用しないのであれば、(少なくとも実行時に) 料金を支払う必要はないと彼は述べています。現状では、orはand と同じくらい効率的に動作します。意味があれば、実行時に余分なオーバーヘッドが発生します (James Curran が指摘したように)。deletenew[]delete[]new[]delete[]newdeletemallocfreedeletedelete[]

于 2008-10-31T03:25:46.290 に答える
10

くそー、私は質問の要点をすべて逃しましたが、元の回答を補足として残します。なぜ私たちが持っているのかdelete[]というと、ずっと前に があったからです。delete[cnt]今日でもdelete[9]orと書いた場合delete[cnt]、コンパイラはその間のものを無視し[]ますが、コンパイルは問題ありません。当時、C++ はまずフロントエンドで処理され、次に通常の C コンパイラに渡されました。彼らはカーテンの下のどこかにカウントを格納するというトリックを行うことができませんでした。また、下位互換性のために、コンパイラはおそらく[]配列のカウントとして の間に指定された値を使用しました。そのような値がない場合、プレフィックスからカウントを取得したため、両方の方法で機能しました。その後、何も入力しなくても[]、すべてが機能しました。今日、私は考えていませんdelete[]必要ですが、実装ではそのように要求されます。

私の元の答え(それは要点を逃しています):

delete単一のオブジェクトを削除します。delete[]オブジェクト配列を削除します。機能するためdelete[]に、実装は配列内の要素の数を保持します。ASM コードをデバッグして、これを再確認しました。私がテストした実装 (VS2005) では、カウントはオブジェクト配列のプレフィックスとして格納されていました。

delete[]単一のオブジェクトで使用すると、count 変数がガベージになるため、コードがクラッシュします。deleteオブジェクト配列に使用すると、矛盾が原因でコードがクラッシュします。これらのケースを今テストしました!

delete配列に割り当てられたメモリを削除するだけです。」別の回答のステートメントは正しくありません。オブジェクトがクラスの場合delete、DTOR を呼び出します。DTOR コードとdeleteオブジェクトにブレークポイントを配置するだけで、ブレークポイントがヒットします。

私に起こったことは、コンパイラとライブラリが、によって割り当てられたすべてのオブジェクトがオブジェクト配列であると想定している場合、単一のオブジェクトまたはオブジェクト配列newを呼び出しても問題ないということです。delete単一のオブジェクトは、カウントが 1 のオブジェクト配列の特殊なケースです。とにかく、私が見逃しているものがあるかもしれません。

于 2008-10-31T07:50:08.393 に答える
9

他の誰もがあなたの質問の要点を見逃しているように見えるので、私は数年前に同じ考えを持っていて、答えを得ることができなかったことを付け加えておきます.

私が考えることができる唯一のことは、単一のオブジェクトを配列として扱うために非常にわずかな余分なオーバーヘッドがあることです (不要な " for(int i=0; i<1; ++i)" )

于 2008-10-31T04:51:54.163 に答える
5

現在、他の回答がないため、これを追加します。

Arraydelete[]は、ポインターから基底へのクラスでは使用できません。コンパイラーは、呼び出し時にオブジェクトの数を格納しますが、オブジェクトnew[]の型やサイズは格納しません (David が指摘したように、C++ ではほとんど支払うことはありません)。使用していない機能の場合)。ただし、スカラーdeleteは基本クラスを介して安全に削除できるため、通常のオブジェクトのクリーンアップと多態的なクリーンアップの両方に使用されます。

struct Base { virtual ~Base(); };
struct Derived : Base { };
int main(){
    Base* b = new Derived;
    delete b; // this is good

    Base* b = new Derived[2];
    delete[] b; // bad! undefined behavior
}

ただし、逆の場合 -- 非仮想デストラクタ -- スカラーdeleteはできるだけ安価である必要があります -- オブジェクトの数や、削除されるオブジェクトのタイプをチェックするべきではありません。これにより、組み込み型または単純な古いデータ型の削除が非常に安価になります。コンパイラーは呼び出すだけ::operator deleteで他に何も必要ないためです。

int main(){
    int * p = new int;
    delete p; // cheap operation, no dynamic dispatch, no conditional branching
}

メモリ割り当てのすべてを網羅しているわけではありませんが、C++ で使用できるメモリ管理オプションの幅広さを明確にするのに役立つことを願っています。

于 2008-10-31T20:32:13.327 に答える
4

Marshall Cline には、このトピックに関する情報があります。

于 2008-10-31T03:29:19.620 に答える
3

delete []delete配列に割り当てられたメモリを削除するだけで、各メンバーのデストラクタが呼び出されることを保証します (型に該当する場合) 。

これは良い読み物です:http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=287

いいえ、配列のサイズは C++ のどこにも保存されません。(この記述が不正確であることを指摘してくれてありがとう。)

于 2008-10-31T03:27:23.993 に答える
1

私はアーロンの答えに少し混乱しており、率直に言って、必要な理由と場所を完全には理解していないことを認めていdelete[]ます。

彼のサンプル コードを使っていくつかの実験を行いました (いくつかのタイプミスを修正した後)。これが私の結果です。タイプミス:~Base関数本体 Base *bが 2 回宣言されている必要がありました

struct Base { virtual ~Base(){ }>; };
struct Derived : Base { };
int main(){
Base* b = new Derived;
delete b; // this is good

<strike>Base</strike> b = new Derived[2];
delete[] b; // bad! undefined behavior
}

コンパイルと実行

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
david@Godel: # No error message

delete[]削除された修正済みプログラム

struct Base { virtual ~Base(){}; };
struct Derived : Base { };

int main(){
    Base* b = new Derived;
    delete b; // this is good

    b = new Derived[2];
    delete b; // bad! undefined behavior
}

コンパイルと実行

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
atest(30746) malloc: *** error for object 0x1099008c8: pointer being freed was n
ot allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

もちろん、delete[] b最初の例で が実際に機能しているかどうかはわかりません。コンパイラエラーメッセージが表示されないことだけを知っています。

于 2013-12-04T14:53:27.877 に答える