web-dev-qa-db-ja.com

C ++:削除と無料、パフォーマンス

  1. 検討してください:

    char *p=NULL;
    free(p) // or
    delete p;
    

    freedeleteおよびpを使用するとどうなりますか?

  2. プログラムの実行に長い時間がかかる場合(たとえば10分)、実行時間を5分に減らす方法はありますか?

26
user41522

New/deleteおよびmalloc/freeに関するパフォーマンスの注意事項:

mallocとfree しないでくださいコンストラクタとデコンストラクタをそれぞれ呼び出します。これは、クラスが自動的に初期化または非初期化されないことを意味します。これは、悪い可能性があります(たとえば、初期化されていないポインター)。 charやdoubleなどのPODデータ型には実際にはctorがないため、これは問題になりません。

newおよびdelete doコンストラクタとデコンストラクタを呼び出します。つまり、クラスインスタンスは自動的に初期化および非初期化されます。ただし、通常はパフォーマンスへの影響があります(単純な割り当てと比較して)が、それはましです。

理由がない限り(reallocなど)、new/mallocの使用に一貫性を保つことをお勧めします。この方法では、依存関係が少なくなり、コードサイズと読み込み時間が短縮されます(ただし、smidginによってのみ)。また、newで割り当てられたものを解放したり、mallocで割り当てられたものを削除したりしても、台無しにはなりません。 (これはおそらくクラッシュを引き起こします!)

61
strager

回答1:free(p)delete pの両方がNULLポインターで正常に機能します。

回答2:コードの遅い部分を見ずに答えることは不可能です。コードをプロファイルする必要があります! Linuxを使用している場合は、Callgrind( Valgrind の一部)を使用して、実行のどの部分が最も時間がかかるかを調べることをお勧めします。

13
activout.se

質問1:何も起こりません。

ISO/IEC 14882(または:C++)の現在のドラフトから:

20.8.15 Cライブラリ[c.malloc]

[_<cstdlib>_の内容、つまり:free lives、]は、標準Cライブラリと同じです([intro.refsを参照してください])ヘッダー_<stdlib.h>_、以下の変更:[この回答に影響を与えるものはありません]。

したがって、ISO/IEC 9899:1999(または:C)から:

7.20.3.2 free関数

[the] ptr [parameter]がnullポインターの場合、アクションは発生しません

再びC++標準から、今回のdeleteについては、次のようにします。

3.7.4.2割り当て解除関数[basic.stc.dynamic.deallocation]

割り当て解除関数に提供される最初の引数の値は、nullポインタ値である可能性があります。その場合、および割り当て解除関数が標準ライブラリで提供されるものである場合呼び出しは無効です

以下も参照してください。

10
cic

NULLパラメータを指定してfreeを呼び出したり、NULLオペランドを指定して削除したりしても、何も起こりません。どちらもNULLを受け入れ、アクションを実行しないように定義されています。

実行速度に影響を与える可能性のある、C++コードで変更できるものはいくつもあります。多くの場合、(おおよその順序で)最も役立つものは次のとおりです。

  • 適切なアルゴリズムを使用してください。これは大きなトピックですが、たとえば、要素が最後にのみ追加および削除される場合、std :: listの代わりにstd :: vectorを使用して、コードの実行時間を最近半分にしました。
  • 長い計算を繰り返さないでください。
  • オブジェクトを不必要に作成およびコピーしないでください(ただし、1千万回のベクトルのように、何かを処理している場合を除いて、1分あたり1000万回未満の発生は大きな違いはありませんreally big) 。
  • 最適化してコンパイルします。
  • 一般的に使用される関数(ここでも、10分のランタイムで1億回以上呼び出されるもの)をインラインとしてマークします。

そうは言っても、divideandconquerは完全に正しいです。プログラムが時間を費やして何をしているのかを知らなければ、プログラムを効果的に高速化することはできません。コードがどのように機能するかを知っている場合、これは正しく推測されることもあれば、非常に驚​​くこともあります。したがって、プロファイルを作成するのが最善です。コードをプロファイリングして時間がどこで費やされているかを正確に確認できない場合でも、変更による影響を測定すると、最終的には多くの場合それを理解できます。

4
Steve Jessop

他の人がNULLポインタの削除(または解放)を指摘したように、何もしません。ただし、メモリを割り当てた場合、free()またはdeleteを使用するかどうかは、それらを割り当てるために使用したメソッドによって異なります。たとえば、malloc()を使用してメモリを割り当てた場合は、free()を使用し、newを使用して割り当てた場合は、deleteを使用する必要があります。ただし、メモリ割り当てを混在させないように注意してください。単一の方法を使用して、それらを割り当ておよび割り当て解除します。

2番目の質問については、実際のコードを見ずに一般化することは非常に困難です。それはケースバイケースで取られるべきです。

2
Naveen

質問2:
以前の回答は素晴らしいです。しかし、私は事前最適化について何かを追加したかっただけです。中程度の複雑さのプログラムを想定すると、通常、90/10ルールが適用されます。つまり、実行時間の90%がコードの10%で費やされます。 「最適化された」コードは、多くの場合、読み取りや保守が困難です。したがって、常に最初に問題を解決してから、ボトルネックがどこにあるかを確認します(プロファイリングは優れたツールです)。

2
E Dominique

すべて良い答えです。

パフォーマンスの問題について、 this はほとんどの人が機能するとは考えられない方法を提供しますが、驚くほどうまくいく方法を知っている人もいます。

90/10ルールは真です。私の経験では、通常、複数の問題点があり、それらは通常、コールスタックの中間レベルにあります。これらは、一般的なデータ構造の過剰使用が原因で発生することがよくありますが、実際に問題であることが証明されていない限り、修正するべきではありません。パフォーマンスの問題は驚くほど予測不可能です。

単一のパフォーマンスの問題を修正しても、必要なスピードアップが得られない可能性がありますが、修正するたびに、残りの問題の残りの時間が占める割合が大きくなるため、見つけやすくなります。スピードアップは複合的に組み合わされているため、最終結果に驚くかもしれません。

修正できる重要な問題が見つからなくなった場合は、できる限りのことを行いました。場合によっては、その時点で、再設計(コード生成の使用など)により、さらに高速化が開始されることがあります。

1
Mike Dunlavey