Initializing array member objects in c++

Started by
35 comments, last by Fruny 19 years, 10 months ago
Quote:Original post by Fruny

&Plane3::mPx is a pointer to member, of type int Plane3::*. I store one for each member I want to index in an array - which I put in a static member because, in my opinion, that's the best place to put it; it is not a requirement.


You are keeping it in a static because it's not going to change between instances of the class right, which seems perfectly reasonable to me.

Sweet.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Advertisement
Fruny -> by the way I rated you one notch off the top just to see what would happen - which is why your score is over 1000 I guess ;-)
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
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.
did you just use the "const" keyword somewhere in the mArr declaration then, or did you have to make the change in the asm?
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
The changed pointer to member code is in the second source box. It's a minor change to the c++ code.
Quote:Original post by asp_

The changed pointer to member code is in the second source box. It's a minor change to the c++ code.

//////////////////////////////////////////////////////////////////////////////////////////////////
// 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.
//////////////////////////////////////////////////////////////////////////////////////////////////



Oh yeah, missed that. Well it's all very impressive, and I feel like I've learnt sommit new ;)
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Good catch. You say the const version generates code equivalent to regular array indexing (to be honest, I'm not that good at reading ASM)? That's better than I would have expected.

Now you have something to point to, next time somebody claims that const is useless. :)
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement