2

私自身の好奇心のための質問です。メソッドを作成するときは、コピー/破棄パラダイムを使用するのが最善であると何度も聞いています。したがって、次のような方法がある場合:

OtherClass MyClass::getObject(){
    OtherClass returnedObject;
    return returnedObject;
}

おそらくコンパイラは、基本的にメソッドをインライン化し、を呼び出すメソッドのスタック上にクラスを生成することによって、これを最適化しますgetObject。このようなループでそれがどのように機能するのだろうかと思います

for(int i=0; i<10; i++){
    list.push_back(myClass.getObject());
}

コンパイラOtherClassはスタックに10個のインスタンスを配置して、このメソッドをインライン化し、最適化されていないコードで発生するコピーと破棄を回避できるようにしますか?このようなコードはどうですか?

while(!isDone){
     list.push_back(myClass.getObject());
    //other logic which decides rather or not to set isDone
}

この場合、コンパイラは何回getObject呼び出されるかを知ることができなかったので、スタックに何かを事前に割り当てることができると考えられます。したがって、インライン化は行われず、メソッドが呼び出されるたびに、コピーOtherObject

私は、すべてのコンパイラーが異なっていること、そしてこれはむしろコンパイラーがこのコードが最適であると信じていることに依存していることを理解しています。私は一般的な言葉で話しているだけですが、ほとんどのコンパイルはどのように応答する可能性が最も高いでしょうか?この種の最適化がどのように行われるのか興味があります。

4

4 に答える 4

2
for(int i=0; i<10; i++){
    list.push_back(myClass.getObject());
}

コンパイラは、このメソッドをインライン化し、最適化されていないコードで発生するコピーと破棄を回避できるように、スタックに OtherClass の 10 個のインスタンスを配置しますか?

コピーと破棄を回避するためだけに 10 個のインスタンスをスタックに置く必要はありません... 戻り値の最適化の有無にかかわらず、1 つのオブジェクトが返されるスペースがある場合、そのスペースを 10 回再利用できます-コピーするたびにリストpush_backによって、同じスタックスペースから新しいヒープ割り当てメモリに。

新しいメモリを割り当て、 myClass.getObject() がそのメモリに直接オブジェクトを構築するように手配することも、コンパイラの権利の範囲内です。

さらに、オプティマイザーがループをアンロールすることを選択した場合、オーバーラップや並列性があっても、myClass.getObject() を 10 回呼び出す可能性があります。そのような状況では、実際には 10 個の戻りオブジェクト用のスペースが必要になります。また、それがスタック上にあるか、奇跡的に巧妙な最適化によって直接ヒープ メモリにあるかは、コンパイラ次第です。

実際には、コンパイラーはスタックからヒープにコピーする必要があると思います。主流のコンパイラーがヒープメモリーでの直接構築を手配するほど賢いかどうかは非常に疑わしいです。ただし、ループ展開と RVO は一般的な最適化です。しかし、両方が開始されたとしても、getObject への呼び出しごとに、スタック上に結果がシリアルに作成され、それがヒープにコピーされることを期待しています。

「知りたい」場合は、独自のコンパイラをテストするコードを記述してください。コンストラクターに「this」ポインター値を書き出すことができます。

次のようなコードはどうでしょうか。

while(!isDone){
     list.push_back(myClass.getObject());
    //other logic which decides rather or not to set isDone
}

コードが複雑で慣用的でないほど、コンパイラの作成者がそのコードを最適化することができず、気にすることもありません。ここでは、私たちが推測できる複雑さのレベルさえ示していません。コンパイラと最適化の設定を試してみてください....

于 2012-06-22T15:18:20.797 に答える
1

どの OS 上のどのコンパイラのどのバージョンかによって異なります。

コンパイラにそのアセンブリを出力させてみませんか。自分で見てみることができます。

gcc - http://www.delorie.com/djgpp/v2faq/faq8_20.html

Visual Studio - Visual C++ プロジェクトからアセンブリ レベルのコードを表示する

于 2012-06-22T14:38:25.467 に答える
1

一般に、最適化コンパイラは、結果として得られるプログラムの動作が目に見えて変更されない限り、コードに変更を加えることができます。その関数がプログラマーによってinlineマークされていなくても、これには ing 関数が含まれます (または含まれません) 。inline

于 2012-06-22T14:39:16.103 に答える
0

コンパイラが気にしなければならない唯一のことは、プログラムの動作です。最適化によってプログラム ロジックとデータが損なわれない場合、最適化は有効です。入ってくるもの (すべての可能なプログラム入力) は、最適化なしと同じように出てくる必要があります (すべての可能なプログラム出力)。

この特定の最適化が可能かどうか (それが実際の最適化であるかどうかは別のことです!) は、ターゲット プラットフォームの命令セットと、それを実装できるかどうかによって異なります。

于 2012-06-22T14:45:27.460 に答える