2012-03-02 13 views
2

マッピング(数学的意味で)を表現するいくつかのクラス、つまりf:RxR^n - > R^nを実装しています。 1)参照としてstd :: arrayをとり、それを変更します または 2)std :: arrayを返します(値または参照によって、わかりません)std :: arrayを返す

オプション2の構文は、コードが私が表現しようとしている数学のように見えると思うので、私にとってはもっと望ましいですが、私は不必要に物をコピーして望ましくないオーバーヘッド。例えば、私が持っていた場合:

// Function f declaration 
std::array<double, 4> f(double t, const std::array<double, 4> & x); 

// Some code snippet that uses f 
std::array<double, 4> x = {0.0, 1.0, 2.0, 3.0}; 
double t = 0.0; 
std::array<double, 4> dxdt = f(t, x); 

を私はコピーが最後の行に実行されている、またはどのように私はそれがが起こらないことを保証できるかどうかを判断するにはどうすればよいですか?

f()の定義内で、コピーコンストラクタを呼び出さずに返されるようにするには何が必要ですか?クライアントがポインタやスマートポインタを使う必要がないように、使い方を単純にしたいのですが、これは必要でしょうか?

voidを返すようにこれを変更して、引数の1つをstd :: array dxdtにすることができますが、パフォーマンスの低下やメモリリークの問題がない限り、戻り値の構文がより好きです。

答えて

8

コピーの最適化はコンパイラーの問題であるため、気にする必要はありません。しかし、コンパイラは依然としてチューニングベースのマシンであり、最適化自体を作成することはできません。私の知る限り、今日のコンパイラのほとんどを知っている

が機能すれば、動作します。

  • は、単一のreturn文を持っているか...
  • はすべて同じ変数に

を返す複数のリターンを持っていますコンパイラは、関数呼び出しが属する式によって評価されなければならない場所で、その変数をスタックに割り当てます。 コピーは生成されません。

あなたの関数に異なる式を返す複数の出口がある場合、これはいくつかの特定の場合には実行できません。

したがって、ワイドオブジェクトを返さなければならない場合は、それを宣言して、すべてのreturn文がそれを返すようにしてください。

+0

ありがとう!私は、関数呼び出しが最後のパラメータを "出力"パラメータであることに固執するつもりです。なぜなら、関数呼び出しは、保持している変数を宣言している場所と同じ行には存在しないからです戻り値は、このように、私はコピーが作成されていないことを確かに知っています。 – hazelnusse

+0

@ hazelnusse:もしあなたがそれを行うことができれば、戻り値を "出力パラメータ"にしておけば、すべての返信文が同じ変数を明示的に*返すことができます。したがって、名前付き戻り値の最適化が始まります。だから問題は何ですか? –

+0

@hazelnusse: "...同じ行にはありません..." "行"については決して話しませんでした。 –

1

私はあなたが不要なコピーを心配する必要はないと信じています。コンパイラはこれらのことを最適化するのにはかなり良いです。 RVO(Return Value Optimization)を使用して不要なコピーを排除できます。また、C++ 11でサポートされているコンパイラを使用している場合は、moveのセマンティクスのためにコピーがさらに減少します。

+5

'std :: array 'の特別なケースでは、移動セマンティクスはほとんど価値がありません。移動セマンティクスは、間接指定(動的に割り当てられたメモリとポインタ)がある場合にのみ役立ちます。 –

0

あなたが参照して戻った場合、コピー操作は行われません(実際には4バイトのメモリアドレスを処理しています)。

std::array<double, 4> f(double t, const std::array<double, 4> & x); 

...に変換することができ...

std::array<double, 4>& f(double t, const std::array<double, 4> & x); 

それはなるため(戻り値はない関数自体内のローカルスタック割り当てられた変数であることを条件とします返された後にぶら下がった参照)。

場合によってはコンパイラが自動的にこれを行うこともありますが、それについて明示的に言えば、にはが確実にコピーされます。

+0

Hum ...これはグローバル変数を参照する必要があります。あまりよくない。 –

2

これは非常に一般的な使用例であり、コンパイラがよく理解しています。ただし、最適化を有効にしてください。もう1つ、配列が4 doubleの場合は、これより前に最適化することがより重要になるでしょう。あなたがそれを必要としている(つまり、あなたが測定した)ことが悪であることを知る前に最適化することを忘れないでください。

実際にコピーが存在しないことを確認したい場合は、アセンブリコードを見ることができます(どのようにコンパイラ/ツールに依存するか)。

あなたは派生しない限り、別の方法として、あなたはコピーコンストラクタ彼らは呼び出されませんが、あなたはstd::array<>でそれを行うことはできませんことを確認するには、代入演算子の中で何かを印刷する独自のクラスを書くことができそれは許可されていません(コンパイルして実行します)。

関連する問題