検討:
char *p=NULL; free(p) // or delete p;
free
とdelete
onを使用するとどうなりp
ますか?プログラムの実行に長い時間がかかる場合 (たとえば 10 分)、実行時間を 5 分に短縮する方法はありますか?
7 に答える
new/delete および malloc/free に関するいくつかのパフォーマンス ノート:
malloc と freeは、それぞれコンストラクターとデコンストラクターを呼び出しません。これは、クラスが自動的に初期化または初期化解除されないことを意味します。これは問題になる可能性があります (初期化されていないポインターなど)! ただし、char や double などの POD データ型には実際には ctor がないため、これは問題ではありません。
new と deleteは、コンストラクターとデコンストラクターを呼び出します。これは、クラス インスタンスが自動的に初期化および初期化解除されることを意味します。ただし、通常は (単純な割り当てと比較して) パフォーマンス ヒットがありますが、それは良いことです。
理由 (realloc など) がない限り、new/malloc の使用法と一貫性を保つことをお勧めします。このようにして、依存関係が少なくなり、コードのサイズと読み込み時間が短縮されます (ただし、smidgin だけです)。また、new で割り当てられたものを解放したり、malloc で割り当てられたものを削除したりして、混乱することもありません。(これはおそらくクラッシュの原因となります!)
回答 1: どちらもNULL ポインターで問題なく動作しますfree(p)
。delete p
回答 2: コードの遅い部分を確認せずに回答することはできません。コードをプロファイリングする必要があります。Linux を使用している場合は、Callgrind ( Valgrindの一部) を使用して、実行のどの部分に最も時間がかかるかを調べることをお勧めします。
質問 1: 何も起こりません。
ISO/IEC 14882 (または: C++) の現在のドラフトから:
20.8.15 C ライブラリ [c.malloc]
[の
<cstdlib>
、つまり、どこにfree
住んでいるか] の内容は、標準 C ライブラリ [(そのための intro.refs を参照)] header と同じですが<stdlib.h>
、次の変更があります: [この回答に影響を与えるものは何もありません]。
したがって、ISO/IEC 9899:1999 (または: C) から:
7.20.3.2
free
関数[the]
ptr
[parameter] が null ポインターの場合、アクションは発生しません。
delete
今回の情報については、再び C++ 標準から:
3.7.4.2 解放関数 [basic.stc.dynamic.deallocation]
割り当て解除関数に指定された最初の引数の値は、NULL ポインター値である可能性があります。その場合、および割り当て解除関数が標準ライブラリで提供されているものである場合、呼び出しは効果がありません。
以下も参照してください。
NULLパラメータを使用してfreeを呼び出すか、NULLオペランドを使用して削除しても、何も起こりません。どちらもNULLを受け入れ、アクションを実行しないように定義されています。
C ++コードで変更できることはいくつもあり、実行速度に影響を与える可能性があります。多くの場合、(おおよその順序で)最も役立つものは次のとおりです。
- 優れたアルゴリズムを使用してください。これは大きなトピックですが、たとえば、要素が最後にのみ追加および削除された場合、最近、std::listの代わりにstd::vectorを使用して、コードの実行時間を半分にしました。 。
- 長い計算を繰り返さないでください。
- オブジェクトを不必要に作成およびコピーすることは避けてください(ただし、1分間に1,000万回未満しか発生しない場合は、1,000万個のアイテムのベクトルなど、非常に大きなものを処理しない限り、大きな違いはありません)。
- 最適化を使用してコンパイルします。
- よく使用される関数(ここでも、10分間の実行時に1億回以上呼び出される関数)をインラインとしてマークします。
そうは言っても、divideandconquerは絶対に正しいです。プログラムが何をしているのかを知らない限り、プログラムを効果的にスピードアップすることはできません。コードがどのように機能するかを知っていれば、これを正しく推測できる場合もあれば、非常に驚くべき場合もあります。したがって、プロファイリングするのが最善です。コードのプロファイルを作成して時間が費やされた場所を正確に確認できない場合でも、変更がどのような影響を与えるかを測定すれば、最終的にはそれを理解できることがよくあります。
質問2について:
以前の回答は優れています。しかし、私は事前最適化について何かを追加したかっただけです。中程度の複雑さのプログラムを想定すると、通常は90/10ルールが適用されます。つまり、実行時間の90%がコードの10%に費やされます。「最適化された」コードは、多くの場合、読み取りと保守が困難です。したがって、常に最初に問題を解決してから、ボトルネックがどこにあるかを確認してください(プロファイリングは優れたツールです)。
他の人が指摘しているように、NULL ポインターの削除 (または解放) は何もしません。ただし、メモリを割り当てた場合、free() を使用するか削除を使用するかは、それらを割り当てるために使用した方法によって異なります。たとえば、malloc() を使用してメモリを割り当てた場合は free() を使用し、new を使用して割り当てた場合は delete を使用する必要があります。ただし、メモリ割り当てを混在させないように注意してください。それらの割り当てと割り当て解除には単一の方法を使用してください。
2 番目の質問については、実際のコードを見ずに一般化することは非常に困難です。ケースバイケースで取るべきです。
良い答えすべて。
パフォーマンスの問題に関しては、これはほとんどの人がうまくいくとは想像できない方法を提供しますが、驚くほどうまくいくことを知っている人もいます。
90/10 ルールは正しいです。私の経験では、通常、複数の問題点があり、それらは通常、コール スタックの中間レベルにあります。多くの場合、過度に一般的なデータ構造を使用することによって引き起こされますが、実際に問題であることが証明されない限り、何かを修正するべきではありません。パフォーマンスの問題は驚くほど予測不可能です。
パフォーマンスの問題を 1 つでも修正しても、必要なスピードアップが得られない場合がありますが、修正するたびに残りの問題が残りの時間のより多くの割合を占めるようになるため、問題を見つけやすくなります。スピードアップは複合的な方法で組み合わされるため、最終結果に驚くかもしれません.
修正できる重要な問題が見つからなくなった場合は、できる限りのことを行ったことになります。場合によっては、その時点で再設計 (コード生成の使用など) を行うことで、さらに高速化を進めることができます。