在这段代码中,我连续多次访问 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;
};
在此示例中,您实际上可以在 Item2
和 ItemAll
之间使用静态转换。在任何一种情况下,如果您引用 ItemAll.i2
或 Item2::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/