c++ - 是否以某种方式优化了对同一类成员的连续多次访问?

标签 c++ optimization

在这段代码中,我连续多次访问 exitButton.rectangle,我想知道它是否经过优化,因此生成的目标代码不必向 exitButton 请求 rectangle每次:

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

最佳答案

在这种特殊情况下,编译器实际上没有执行任何优化。事实上,在第二种情况下,编译器实际上可能不得不更加努力地工作才能产生同样高效的代码;因为为此它必须解析引用别名。

原因是Rectangle不是指针,而是直接嵌入到MenuItem中。在这种情况下,编译器实际上将整个结构树视为一组平面变量。编译器根据从结构开始的字节偏移来考虑事情。示例:

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

...在结构上等同于:

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

在此示例中,您实际上可以在 Item2ItemAll 之间使用静态转换。在任何一种情况下,如果您引用 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; 作为代码简化工具。它可以使您的代码更易于维护并减少您的一些输入!但它不会帮助编译器完成它的工作,所以如果那是你的目标,请不要打扰。

关于c++ - 是否以某种方式优化了对同一类成员的连续多次访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14087551/

相关文章:

c++ - 如何在 Qt 应用程序中保存 session ?

C++/SDL "initial value of reference to a non-const must be an lvalue"

java - 以 %.7f 格式创建时间戳字符串的更快方法

mysql - mysql中的多列不同

c++ - 如果我的进程在事件之间处于空闲状态,为什么延迟会更大?

c# - 快速校验和散列?

c++ - Linux Standard Base (LSB) AppChecker 可靠吗?

c++ - 将字符串 vector 连接到 std::ostream(如 boost::join)

c++ - 是否可以在不指定包含的情况下创建 dll

algorithm - 优化(并行化)我的 "virtual machine"模型的执行