Fruny,
Quote:
Yup. Do that. I would actually like to see the results.
Like the rest of us the compiler is confused a "little" by the code. The results from real world usage would hopefully not be as bad but still worse than the regular array.
Quote:
Then, tell us if the tradeoff was worth it.
I construct a lot more than I address as an array so yeah it would still be worth it for me. Seems like you can't have the best of both worlds for free ;) If you're really desperate or really sure of the alignment of members across platforms and compilers you could go with the operators I post below.
Obviously the compiler could have optimized it more but due to the complexity of the code it doesn't seem to catch the possible optimizations. I also tried implementing the [] operator I suggested which isn't safe in any way but which the compiler was able to fully optimize. It's a shame the compiler has such hard time optimizing your code Fruny as it's a lot more stable than what I suggested. Maybe the compiler would produce better code if we could guarantee that the elements in the array of member pointers are constants.
Here's the resulting code:
//////////////////////////////////////////////////////////////////////////////////////////////////// CREATING A PLANE3B (EMPTY DEFAULT CONSTRUCTOR), PRINTING EACH MEMBER BY ARRAY ADDRESSING. // CONSTRUCTOR GETS TOTALLY ELIMINATED. CONSTANTS ARE JUST PUSHED ONTO THE STACK.//////////////////////////////////////////////////////////////////////////////////////////////////// ENTRY POINT00401000 >/$ 68 00000840 PUSH 4008000000401005 |. 6A 00 PUSH 000401007 |. 68 00000040 PUSH 400000000040100C |. 6A 00 PUSH 00040100E |. 68 0000F03F PUSH 3FF0000000401013 |. 6A 00 PUSH 000401015 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"0040101A |. E8 A1000000 CALL fruny.004010C00040101F |. 68 00001840 PUSH 4018000000401024 |. 6A 00 PUSH 000401026 |. 68 00001440 PUSH 401400000040102B |. 6A 00 PUSH 00040102D |. 68 00001040 PUSH 4010000000401032 |. 6A 00 PUSH 000401034 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"00401039 |. E8 82000000 CALL fruny.004010C00040103E |. 68 00002240 PUSH 4022000000401043 |. 6A 00 PUSH 000401045 |. 68 00002040 PUSH 402000000040104A |. 6A 00 PUSH 00040104C |. 68 00001C40 PUSH 401C000000401051 |. 6A 00 PUSH 000401053 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"00401058 |. E8 63000000 CALL fruny.004010C00040105D |. 83C4 54 ADD ESP,5400401060 |. 33C0 XOR EAX,EAX00401062 \. C3 RETN//////////////////////////////////////////////////////////////////////////////////////////////////// CREATING A PLANE3A (EMPTY DEFAULT CONSTRUCTOR), PRINTING EACH MEMBER BY ARRAY ADDRESSING. // CONSTRUCTOR ISN'T ELIMINATED, FPU INSTRUCTIONS USED, OVERHEAD WHEN RESOLVING ADDRESS.// OBVIOUSLY THE COMPILER HAS A HARDER TIME OPTIMIZING THIS CODE.//////////////////////////////////////////////////////////////////////////////////////////////////// ENTRY POINT00401000 >/$ 55 PUSH EBP00401001 |. 8BEC MOV EBP,ESP00401003 |. 83E4 F8 AND ESP,FFFFFFF800401006 |. 83EC 28 SUB ESP,2800401009 |. A1 40804000 MOV EAX,DWORD PTR DS:[408040]0040100E |. 8D4404 04 LEA EAX,DWORD PTR SS:[ESP+EAX+4]00401012 |. C74424 04 0000803F MOV DWORD PTR SS:[ESP+4],3F8000000040101A |. C74424 08 00000040 MOV DWORD PTR SS:[ESP+8],4000000000401022 |. C74424 0C 00004040 MOV DWORD PTR SS:[ESP+C],404000000040102A |. C74424 10 00008040 MOV DWORD PTR SS:[ESP+10],4080000000401032 |. C74424 14 0000A040 MOV DWORD PTR SS:[ESP+14],40A000000040103A |. C74424 18 0000C040 MOV DWORD PTR SS:[ESP+18],40C0000000401042 |. C74424 1C 0000E040 MOV DWORD PTR SS:[ESP+1C],40E000000040104A |. C74424 20 00000041 MOV DWORD PTR SS:[ESP+20],4100000000401052 |. C74424 24 00001041 MOV DWORD PTR SS:[ESP+24],411000000040105A |. D940 08 FLD DWORD PTR DS:[EAX+8]0040105D |. 83EC 18 SUB ESP,1800401060 |. DD5C24 10 FSTP QWORD PTR SS:[ESP+10]00401064 |. D940 04 FLD DWORD PTR DS:[EAX+4]00401067 |. DD5C24 08 FSTP QWORD PTR SS:[ESP+8]0040106B |. D900 FLD DWORD PTR DS:[EAX]0040106D |. DD1C24 FSTP QWORD PTR SS:[ESP]00401070 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"00401075 |. E8 B6000000 CALL fruny.004011300040107A |. A1 44804000 MOV EAX,DWORD PTR DS:[408044]0040107F |. D94404 28 FLD DWORD PTR SS:[ESP+EAX+28]00401083 |. 8D4404 20 LEA EAX,DWORD PTR SS:[ESP+EAX+20]00401087 |. 83C4 04 ADD ESP,40040108A |. DD5C24 10 FSTP QWORD PTR SS:[ESP+10]0040108E |. D940 04 FLD DWORD PTR DS:[EAX+4]00401091 |. DD5C24 08 FSTP QWORD PTR SS:[ESP+8]00401095 |. D900 FLD DWORD PTR DS:[EAX]00401097 |. DD1C24 FSTP QWORD PTR SS:[ESP]0040109A |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"0040109F |. E8 8C000000 CALL fruny.00401130004010A4 |. A1 48804000 MOV EAX,DWORD PTR DS:[408048]004010A9 |. D94404 28 FLD DWORD PTR SS:[ESP+EAX+28]004010AD |. 8D4404 20 LEA EAX,DWORD PTR SS:[ESP+EAX+20]004010B1 |. 83C4 04 ADD ESP,4004010B4 |. DD5C24 10 FSTP QWORD PTR SS:[ESP+10]004010B8 |. D940 04 FLD DWORD PTR DS:[EAX+4]004010BB |. DD5C24 08 FSTP QWORD PTR SS:[ESP+8]004010BF |. D900 FLD DWORD PTR DS:[EAX]004010C1 |. DD1C24 FSTP QWORD PTR SS:[ESP]004010C4 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"004010C9 |. E8 62000000 CALL fruny.00401130004010CE |. 83C4 1C ADD ESP,1C004010D1 |. 33C0 XOR EAX,EAX004010D3 |. 8BE5 MOV ESP,EBP004010D5 |. 5D POP EBP004010D6 \. C3 RETN//////////////////////////////////////////////////////////////////////////////////////////////////// CREATING A PLANE3A (EMPTY DEFAULT CONSTRUCTOR), PRINTING EACH MEMBER BY ARRAY ADDRESSING. // USES THE FOLLOWING AS [] OPERATOR://// inline Point3 & // operator[](size_t idx) // { // return (&mP0)[idx]; // }; //// inline const Point3& // operator[](size_t idx) // const // { // return (&mP0)[idx]; // };//// CONSTRUCTOR IS ELIMINATED. AS OPTIMAL AS REGULAR [] OPERATOR BUT HAS SOME NASTY CODE WHICH// MIGHT NOT WORK IN SOME CASES. REQUIRES TIGHTLY PACKED MEMBERS.//////////////////////////////////////////////////////////////////////////////////////////////////// ENTRY POINT00401000 >/$ 68 00000840 PUSH 4008000000401005 |. 6A 00 PUSH 000401007 |. 68 00000040 PUSH 400000000040100C |. 6A 00 PUSH 00040100E |. 68 0000F03F PUSH 3FF0000000401013 |. 6A 00 PUSH 000401015 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"0040101A |. E8 A1000000 CALL fruny.004010C00040101F |. 68 00001840 PUSH 4018000000401024 |. 6A 00 PUSH 000401026 |. 68 00001440 PUSH 401400000040102B |. 6A 00 PUSH 00040102D |. 68 00001040 PUSH 4010000000401032 |. 6A 00 PUSH 000401034 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"00401039 |. E8 82000000 CALL fruny.004010C00040103E |. 68 00002240 PUSH 4022000000401043 |. 6A 00 PUSH 000401045 |. 68 00002040 PUSH 402000000040104A |. 6A 00 PUSH 00040104C |. 68 00001C40 PUSH 401C000000401051 |. 6A 00 PUSH 000401053 |. 68 A0704000 PUSH fruny.004070A0 ; ASCII "%f:%f:%f"00401058 |. E8 63000000 CALL fruny.004010C00040105D |. 83C4 54 ADD ESP,5400401060 |. 33C0 XOR EAX,EAX00401062 \. C3 RETN
Ok while going thru this I decided to change so that we actually guarantee that the pointers to members within the array ARE constant. Guess what I got:
//////////////////////////////////////////////////////////////////////////////////////////////////// CREATING A PLANE3A (EMPTY DEFAULT CONSTRUCTOR), PRINTING EACH MEMBER BY ARRAY ADDRESSING. // USES THE FOLLOWING AS ARRAY TO MEMBERS://// private:// static Point3 Plane3a::* const mArr[3];//// AND DEFINITION:// Point3 Plane3a::* const Plane3a::mArr[3] = { &Plane3a::mP0, &Plane3a::mP1, &Plane3a::mP2 };//// CONSTRUCTOR IS ELIMINATED. AS OPTIMAL AS REGULAR [] OPERATOR.//////////////////////////////////////////////////////////////////////////////////////////////////// ENTRY POINT00401000 >/$ 68 00000840 PUSH 4008000000401005 |. 6A 00 PUSH 000401007 |. 68 00000040 PUSH 400000000040100C |. 6A 00 PUSH 00040100E |. 68 0000F03F PUSH 3FF0000000401013 |. 6A 00 PUSH 000401015 |. 68 AC704000 PUSH fruny.004070AC ; ASCII "%f:%f:%f"0040101A |. E8 A1000000 CALL fruny.004010C00040101F |. 68 00001840 PUSH 4018000000401024 |. 6A 00 PUSH 000401026 |. 68 00001440 PUSH 401400000040102B |. 6A 00 PUSH 00040102D |. 68 00001040 PUSH 4010000000401032 |. 6A 00 PUSH 000401034 |. 68 AC704000 PUSH fruny.004070AC ; ASCII "%f:%f:%f"00401039 |. E8 82000000 CALL fruny.004010C00040103E |. 68 00002240 PUSH 4022000000401043 |. 6A 00 PUSH 000401045 |. 68 00002040 PUSH 402000000040104A |. 6A 00 PUSH 00040104C |. 68 00001C40 PUSH 401C000000401051 |. 6A 00 PUSH 000401053 |. 68 AC704000 PUSH fruny.004070AC ; ASCII "%f:%f:%f"00401058 |. E8 63000000 CALL fruny.004010C00040105D |. 83C4 54 ADD ESP,5400401060 |. 33C0 XOR EAX,EAX00401062 \. C3 RETN
Now the compiler is able to create as optimal code as in the regular array case. What a miss ;) This is a lesson that const IS very important, especially when you're faced with pointers to pointers. So in conclusion it seems like the compiler is just as able to optimize the pointer to member solution as the regular array solution in this simple test case. Thus I see no reason not to use it. I'm off to change my real code now ;)
Let me know if there's any blatant errors in my tests.