11

オブジェクトfoointdouble、カスタムstructclassなど)を考えてみましょう。私の理解は、関数への参照(またはfooへのポインタの渡し)によって、fooを渡すと、ローカルコピー(fooが大きい場合には高価になる可能性がある)を避けるため、パフォーマンスが向上します。参照またはポインタによる値渡しのパフォーマンスコスト?

しかし、回答hereから、64ビットシステム上のポインタは、何が指し示されているかにかかわらず、実際には8バイトのサイズが予想されるようです。私のシステムでは、floatは4バイトです。 fooがタイプfloatであれば、それはポインタを与えるのではなく、値fooをより効率的なに渡すより効率的なです(関数内で他のものより効率的なものを使用するような他の制約はないと仮定します) ?

+4

測定する必要があります。参照/コピーされているものの大きさだけが作用するわけではありません。 – juanchopanza

+0

http://stackoverflow.com/questions/21605579/how-true-is-want-speed-pass-by-value –

+0

要約:ネイティブタイプ(int、float、double)を渡すことは、値より大きい。ほとんどの場合、ポインタはネイティブデータ型と同じかそれ以上の大きさであるだけでなく、オプティマイザが値パラメータよりも参照パラメータを最適化することがはるかに難しいためです。 – MikeMB

答えて

11

"コスト"とは何かを意味し、ホストシステム(ハードウェア、オペレーティングシステム)を操作することができます。

コストメジャーがメモリ使用量の場合、コストの計算は明らかです - コピーされているもののサイズを加算します。

メジャーが実行速度(または「効率」)である場合、ゲームは異なります。ハードウェア(およびオペレーティングシステムおよびコンパイラ)は、専用回路(マシンレジスタおよびそれらの使用方法)によって特定のサイズのものをコピーする操作のパフォーマンスを最適化する傾向があります。

たとえば、あるマシンのアーキテクチャー(マシンレジスター、メモリーアーキテクチャーなど)が「スイートスポット」になるのは一般的です。あるサイズの変数をコピーするのが最も効率的ですが、より小さな変数はそれほどです。より小さな変数を複数コピーする必要があるため、変数を大きくするとコピーにかかるコストが高くなります。コンパイラは小さな値を大きな変数(またはレジスタ)にコピーし、その上で操作を実行してから、値をコピーし直す必要があるため、小さなものもコストがかかる可能性があります。浮動小数点と

例は、ソフトウェアでエミュレートされた(別名float C++で)ネイティブ倍精度浮動小数点(C++で別名double)をサポートするいくつかのCrayスーパーコンピュータ、および単精度のすべての操作を含みます。いくつかの古い32ビットx86 CPUも32ビット整数で内部的に動作し、16ビット整数での操作では32ビットへの変換のためにより多くのクロックサイクルが必要でした(これは現代の32ビットまたは64ビットの整数では当てはまりません) 32ビットレジスタへの/からの16ビット整数のコピー、およびその上での操作を可能にし、そのようなペナルティはより少ない)。

非常に大きな構造体を値でコピーすることは、そのアドレスを作成してコピーするよりも効率が悪くなります。しかし、上記のような要因のために、「値でそのサイズのものをコピーする」と「そのアドレスを渡すのが最善」との間のクロスオーバーポイントはあまり明確ではありません。

ポインタおよび参照は、同様の方法で実装される傾向があります(たとえば、参照渡しはポインタを渡すのと同じ方法で実装できます)が、これは保証されません。

唯一の方法は、測定することです。そして、測定値がシステムによって異なることを認識してください。

+2

実際のアーキテクチャーの例を知っていますか?より小さな型(例えばchar)を渡す方が、より大きな型(intまたはポインターのような)を渡すよりも高価ですか? – MikeMB

+0

ええ、大丈夫、いくつかの例が追加されました。 – Peter

+0

ありがとう、しかし、ポインタ/参照渡しの値渡しの質問に関連するこれらの例のいずれかですか?結局のところ、浮動小数点を渡すことではなく、二重に渡すことではありません。 – MikeMB

3

fooの型がfloatの場合、fooを値渡しする方が効率的ですか?

フロートを値で渡す方が効率的です。私はそれがより効率的であると期待しています。あなたが言ったことの一部に起因します。浮動小数点は、あなたが記述するシステム上のポインタよりも小さくなります。しかし、さらに、ポインタをコピーするときには、関数内の値を取得するためにポインタを逆参照する必要があります。ポインターによって追加されたインダイレクションは、パフォーマンスに大きな影響を与える可能性があります。

効率の差はごくわずかです。特に、関数をインライン化して最適化を有効にすることができれば、違いはないでしょう。

フロートをケースで値渡しすることでパフォーマンスが向上するかどうかは、測定することでわかります。プロファイリングツールを使用して効率を測定できます。

あなたはポインタを参照に置き換えることができますが、回答は引き続き同等に適用されます。

リファレンスを使用する際のオーバーヘッドはありますか?ポインタを逆参照する必要がある方法はありますか?

はい。参照は、ポインタとまったく同じパフォーマンス特性を持つ可能性があります。参照またはポインタを使用して意味的に同等のプログラムを書くことが可能な場合は、おそらく同じアセンブリを生成することになります。


ポインタで小さなオブジェクトを渡すと、それをコピーするよりも高速になる場合は、確かにそれは、同じサイズのオブジェクトのための真のだろう、あなたは同意しないだろうか。ポインタへのポインタはどうですか、それはポインタのサイズに関するものですよね? (まったく同じサイズです)ああ、ポインタもオブジェクトです。そのため、オブジェクト(ポインタなど)をポインタで渡す方がオブジェクト(ポインタ)をコピーするよりも速い場合は、ポインタへのポインタへのポインタをポインターに渡すとポインタへのポインタがプロガームよりも速くなりますポインタを使用していないポインターよりもまだ少ないポインターを使用しています...ここで効率の無限のソースを発見しました:)

+0

リファレンスを使用する際のオーバーヘッドはありますか?ポインタを逆参照する必要がある方法はありますか? –

+0

@space_voyagerはポインタと同じです。私は編集を加えました。 – user2079303

2

パフォーマンスが非常に重要なシナリオをテストする必要がありますが、特定の方法でコードを生成するようコンパイラに強制しようとすると非常に注意が必要です。

コンパイラのオプティマイザは、最終的な結果がほぼ同じであれば、どのような方法ででもコードを書き直すことができます。

浮動小数点値を渡すには浮動小数点数のコピーを作成する必要があるが、適切な条件で浮動小数点数を渡すと、元の浮動小数点をCPU浮動小数点レジスタに格納し、そのレジスタを"reference"パラメータを関数に渡します。対照的に、コピーを渡すと、コンパイラはレジスタの内容を保持するためにコピーを格納する場所を見つけなければならず、さらに悪いことに、レジスタを使用することができない可能性がありますオリジナルを保持しています(これは再帰関数で特に当てはまります)。

この違いは、コンパイラーがコピーされたパラメーターで元の値を変更できないことを保証する必要がないため、参照によってインライン化のコストが削減されるインライン化可能な関数への参照を渡す場合にも重要です。

より多くの言語を使用することで、自分のやりたいことを説明することに集中することができればなるほど、コンパイラは創造的な方法で自分の仕事を見つけることができます。C++では、一般的に、パフォーマンスを心配するのではなく、可能な限り明確かつ簡単に記述したいことに焦点を当てるのが一般的です。どのようにして作業をしたいのか記述しようとすると、コンパイラがコードを最適化する作業をしなくなることがよくあります。

+1

通常、これは逆です:パラメータを参照/ポインタで渡すと、実際にはそのパラメータは常にメモリに書き込まれますが、値を渡すとレジスタにデータが保持されることがあります。 – MikeMB

+0

@MikeMB - これは私が上記で提示したシナリオでは当てはまりません。元のコピーはレジスタに保存されています。値渡しとは、元の内容を保持するために別のコピーを必要とするため、利用可能な追加レジスタを使用する必要があります。レジスタが少なすぎるため、レジスタ最適化全体をメモリに展開する必要があります。対照的に、参照渡しによりコンパイラは両方のコードに同じレジスタを共有することができます(特に関数がインライン化されている場合)。私はこれが一般的なシナリオだとは言いませんが、確かに可能です。 –

+0

関数のインライン化が行われないと仮定します。次に、私が知っている呼び出し規約上の参照手段として、元のメモリ位置へのポインタ**が関数に渡され、ポインタとして実際に値がメモリに格納される必要があることを渡しますレジスタを指すことはできません。値渡しのときには、あるレジスタから別のレジスタに偽物をコピーする必要があります(値が関数呼び出しの後に使用されていない場合ではありません)が、メモリに格納する必要はありません。 – MikeMB

関連する問題