2

このコードでは、exitButton.rectangleに連続して数回アクセスし、生成されたオブジェクトコードが毎回要求する必要がないように最適化されているかどうか疑問に思いましexitButtonrectangle

struct MenuItem {
    Rectangle rectangle;
};

MenuItem exitButton;

exitButton.rectangle.top = 383;
exitButton.rectangle.height = 178;
exitButton.rectangle.left = 0;
exitButton.rectangle.width = 1024;

最適化を保証するために、代わりにこのようなものを書く必要がありますか?

Rectangle &tempRectangle = exitButton.rectangle;

tempRectangle.top = 383;
tempRectangle.height = 178;
tempRectangle.left = 0;
tempRectangle.width = 1024;

同じですが、構造体の代わりにクラスを使用しますか?前もって感謝します。

編集

g ++ -o0、参照なし:

    CPU Disasm
Address   Hex dump          Command                                  Comments
004013B0  /$  55            PUSH EBP                                 ; CppTest.004013B0(guessed void)
004013B1  |.  89E5          MOV EBP,ESP
004013B3  |.  83E4 F0       AND ESP,FFFFFFF0                         ; DQWORD (16.-byte) stack alignment
004013B6  |.  83EC 10       SUB ESP,10
004013B9  |.  E8 42060000   CALL 00401A00                            ; [CppTest.00401A00
004013BE  |.  C70424 7F0100 MOV DWORD PTR SS:[LOCAL.4],17F
004013C5  |.  C74424 04 B20 MOV DWORD PTR SS:[LOCAL.3],0B2
004013CD  |.  C74424 08 000 MOV DWORD PTR SS:[LOCAL.2],0
004013D5  |.  C74424 0C 000 MOV DWORD PTR SS:[LOCAL.1],400
004013DD  |.  B8 00000000   MOV EAX,0
004013E2  |.  C9            LEAVE
004013E3  \.  C3            RETN

g ++ -o0、参照:

CPU Disasm
Address   Hex dump          Command                                  Comments
004013B0  /$  55            PUSH EBP                                 ; CppTest.004013B0(guessed void)
004013B1  |.  89E5          MOV EBP,ESP
004013B3  |.  83E4 F0       AND ESP,FFFFFFF0                         ; DQWORD (16.-byte) stack alignment
004013B6  |.  83EC 20       SUB ESP,20
004013B9  |.  E8 62060000   CALL 00401A20                            ; [CppTest.00401A20
004013BE  |.  8D4424 0C     LEA EAX,[LOCAL.5]
004013C2  |.  894424 1C     MOV DWORD PTR SS:[LOCAL.1],EAX
004013C6  |.  8B4424 1C     MOV EAX,DWORD PTR SS:[LOCAL.1]
004013CA  |.  C700 7F010000 MOV DWORD PTR DS:[EAX],17F
004013D0  |.  8B4424 1C     MOV EAX,DWORD PTR SS:[LOCAL.1]
004013D4  |.  C740 04 B2000 MOV DWORD PTR DS:[EAX+4],0B2
004013DB  |.  8B4424 1C     MOV EAX,DWORD PTR SS:[LOCAL.1]
004013DF  |.  C740 08 00000 MOV DWORD PTR DS:[EAX+8],0
004013E6  |.  8B4424 1C     MOV EAX,DWORD PTR SS:[LOCAL.1]
004013EA  |.  C740 0C 00040 MOV DWORD PTR DS:[EAX+0C],400
004013F1  |.  B8 00000000   MOV EAX,0
004013F6  |.  C9            LEAVE
004013F7  \.  C3            RETN
4

2 に答える 2

3

最初に2番目の質問を取り上げると、クラスと構造体の違いはありません(少なくとも、正常なコンパイラーの場合)。2つの違いは、メンバーのデフォルトのアクセシビリティ(クラスの場合はプライベート、構造体の場合はパブリック)だけです。

最適化を確実にする唯一の方法はオブジェクトコードを調べることですが、合理的なコンパイラは、同じ一連の参照を使用して繰り返しアクセスしていると判断し、自動的にレジスタを使用して参照することを期待exitButton.rectangleします。連続アクセスの場合。

すべての最適化をオフにすると、そうではないかもしれませんが、基本的にすべての最適化が許可されているので、それを期待できます-この最適化は何年もの間よく知られています(基本的には一般的な部分式除去です)。

于 2012-12-30T01:44:34.610 に答える
3

この特定のケースでは、コンパイラが実行する最適化は実際にはありません。実際、2番目のケースでは、同等の効率のコードを生成するために、コンパイラーは実際にもっと一生懸命働かなければならない場合があります。そのためには、参照エイリアスを解決する必要があるためです。

その理由は、Rectangleがポインタではなく、に直接埋め込まれているためMenuItemです。このような場合、コンパイラは実際には構造ツリー全体を変数のフラットセットと見なします。コンパイラは、構造体の先頭からオフセットされたバイトの観点から物事を考えます。例:

struct Item1 {
    int i1, i2, i3;
};
struct Item2 {
    Item1  item1;
    int    t1, t2;
};

...内部的には次のものと構造的に同等です。

struct ItemAll {
    int i1, i2, i3;
    int t1, t2;
};

この例ではItem2、との間で静的キャストを実際に使用できます。ItemAllいずれの場合も、いずれかを参照するItemAll.i2Item2::Item1.i2、コンパイラが内部的にそれをと見なす場合variable_base_address + sizeof(int)同じことがクラスと構造体にも当てはまります。

気にする必要があるのは、を使用しているときです。-> operatorたとえば、構造体が次のように設計されている場合です。

struct MenuItem {
    Rectangle* rectangle;
};

この場合、コンパイラは、の内容にアクセスするために追加の間接参照ステップを実行する必要がありますRectangle。最適化を有効にすると、最新のコンパイラーは可能な限り間接参照を最適化します。問題ない。問題が発生する可能性があるのは、CPUで使用可能なレジスタを単に超えるインターリーブ逆参照が多数ある場合です。

struct MenuItem {
    Rectangle* rect1;
    Rectangle* rect2;
    Point*     point1;
    Point*     point2;
};

menuItem.rect1->top = 50;
menuItem.rect2->top = 50;
menuItem.point1->x  = 33;
menuItem.point2->x  = 45;

menuItem.rect1->bottom = 450;
menuItem.rect2->bottom = 450;
// etc...

上記の場合、コンパイラはベースレジスタとして使用するのに適したレジスタを使い果たし、後で使用するために間接参照を冗長に再計算する必要があります(この特定の例では、これらはイミディエートを割り当てているため、レジスタが不足することはありませんが、可変演算が含まれている場合、チャンスははるかに高くなります)。もちろん、この場合も、すべてのrect1割り当てがペアになるように並べ替えるのは簡単です。ただし、単純な割り当てよりも複雑なことを行う場合は、それも不可能な場合があります。

ただし、この場合、参照を使用しても役に立ちません。コンパイラは、ポインタの逆参照を同じ方法でスピルして再ロードする必要があります。

結論:Rectangle& var = menuItem.var;コード簡略化ツールとして自由に使用してください。これにより、コードの保守が容易になり、入力の一部を減らすことができます。しかし、それはコンパイラーがその仕事をするのを助けないので、それがあなたの目的であるならば、気にしないでください。

于 2012-12-30T02:37:46.927 に答える