• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            asm, c, c++ are my all
            -- Core In Computer
            posts - 139,  comments - 123,  trackbacks - 0

            /********************************************\
            |????歡迎轉(zhuǎn)載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
            \********************************************/


            C++對象模型(14) - 3.6 Pointer to Data Members
            作者: Jerry Cat
            時間: 2006/11/23
            鏈接:?
            http://www.shnenglu.com/jerysun0818/archive/2006/11/23/15593.html


            3.6 Pointer to Data Members:
            ;-----------------------------------------------------------------------

            Consider the following Point3d class declaration. It declares a virtual function, a static data member, and three coordinate values:

            class Point3d {
            public:
            ?? virtual ~Point3d(); //虛表指針的位置"非頭即尾"
            ?? // ...
            protected:
            ?? static Point3d origin;
            ?? float x, y, z;
            };

            What does it mean, then, to take the address of one of the coordinate members? For example, what value should the following yield?

            &3d_point::z;
            It is going to yield the z-coordinate's offset within the class object. Minimally, this has to be the size of the x and y members, since the language requires the members within an access level be set down in the order of declaration.

            3.6 Pointer to Data Members
            Pointers to data members are a somewhat arcane but useful feature of the language, particularly if you need to probe at the underlying member layout of a class. One example of such a probing might be to determine if the vptr is placed at the beginning or end of the class. A second use, presented in Section 3.2, might be to determine the ordering of access sections within the class. As I said, it's an arcane, although potentially useful, language feature.

            Consider the following Point3d class declaration. It declares a virtual function, a static data member, and three coordinate values:

            class Point3d {
            public:
            ?? virtual ~Point3d();
            ?? // ...
            protected:
            ?? static Point3d origin;
            ?? float x, y, z;
            };
            The member layout for each Point3d class object contains the three coordinate values in the order x, y, z and a vptr. (Recall that origin, the static data member, is hoisted outside the individual class object.) The only implementation aspect of the layout is the placement of the vptr. The Standard permits the vptr to be placed anywhere within the object: at the beginning, at the end, or in between either of the three members. In practice, all implementations place it either at the beginning or at the end.

            What does it mean, then, to take the address of one of the coordinate members? For example, what value should the following yield?

            &3d_point::z;
            It is going to yield the z-coordinate's offset within the class object. Minimally, this has to be the size of the x and y members, since the language requires the members within an access level be set down in the order of declaration.

            At the compiler's discretion, however, the vptr may be placed either before, in-between, or after the coordinate members. Again, in practice, the vptr is either placed at the beginning or at the end of the class object. On a 32-bit machine, floats are 4 bytes each, so we would expect the value to be either 8 bytes without an intervening vptr or 12 bytes with it. (The vptr, and pointers in general, use 4 bytes on a 32-bit architecture.)
            ?
            That expectation, however, is off by one—a somewhat traditional error for both C and C++ programmers.

            The physical offset of the three coordinate members within the class layout are, respectively, either 0, 4, and 8 if the vptr is placed at the end or 4, 8, and 12 if the vptr is placed at the start of the class. The value returned from taking the member's address, however, is always bumped up by 1. Thus the actual values are 1, 5, and 9, and so on. Do you see why Bjarne decided to do that?

            The problem is distinguishing between a pointer to no data member and a pointer to the first data member. Consider for example:

            float Point3d::*p1 = 0;
            float Point3d::*p2 = &Point3d::x;

            // oops: how to distinguish?
            if ( p1 == p2 ) {
            ?? cout << " p1 & p2 contain the same value — ";
            ?? cout << " they must address the same member!" << endl;
            }

            To distinguish between p1 and p2, each actual member offset value is bumped up by 1. Hence, both the compiler (and the user) must remember to subtract 1 before actually using the value to address a member.

            Given what we now know about pointers to data members, we find that explaining the difference between

            &Point3d::z;
            and
            &origin.z

            is straightforward. Whereas taking the address of a nonstatic data member yields its offset within the class, taking the address of a data member bound to an actual class object yields the member's actual address in memory. The result of

            &origin.z
            adds the offset of z (minus 1) to the beginning address of origin. origin是個實例化的類Point3d的靜態(tài)數(shù)據(jù)成員. The value returned is of type

            float*
            not
            float Point3d::*

            because it refers to an specific single instance(靜態(tài)成員屬于類而非類的各具體實例對象), much the same as taking the address of a static data member.

            Under multiple inheritance, the combination of a second (or subsequent) base class pointer to a member bound to a derived class object is complicated by the offset that needs to be added. For example, if we have

            struct Base1 { int val1; };
            struct Base2 { int val2; };
            struct Derived : Base1, Base2 { ... };

            void func1( int d::*dmp, d *pd )
            {
            ?? // expects a derived pointer to member
            ?? // what if we pass it a base pointer?
            ?? pd->*dmp;
            }
            void func2( d *pd )
            {
            ?? // assigns bmp 1
            ?? int b2::*bmp = &b2::val2;

            ?? // oops: bmp == 1,
            ?? // but in Derived, val2 == 5
            ?? func1( bmp, pd )
            }
            bmp must be adjusted by the size of the intervening Base1 class when passed as the first argument to func1(). Otherwise, the invocation of

            pd->*dmp;
            within func1() will access Base1::val1, not Base2::val2 as the programmer intended. The specific solution in this case is

            // internal transformation by compiler
            func1( bmp + sizeof( Base1 ), pd );
            In general, however, we cannot guarantee that bmp is not 0 and so must guard against it:

            // internal transformation
            // guarding against bmp == 0
            func1( bmp ? bmp + sizeof( Base1 ) : 0, pd );

            二. Efficiency of Pointers to Members:

            The following sequence of tests attempts to gain some measure of the overhead associated with using pointers to members under the various class representations of the 3D point. In the first two cases, there is no inheritance. The first case takes the address of a bound member:

            float *ax = &pA.x;
            for the three coordinate members of points pA and pB. The assignment, addition, and subtraction look as follows:

            *bx = *ax - *bz;
            *by = *ay + *bx;
            *bz = *az + *by;
            The second case takes the address of a pointer to data member:

            float pt3d::*ax = &pt3d::x;
            for the three coordinate members. The assignment, addition, and subtraction use the pointer to data member syntax, binding the values to the objects pA and pB:

            pB.*bx = pA.*ax - pB.*bz;
            pB.*by = pA.*ay + pB.*bx;
            pB.*bz = pA.*az + pB.*by;
            Recall that the direct data member exercise of this function, executed in Section 3.5, ran with an average user time of 0.80 with optimization turned on and 1.42 with optimization turned off for both compilers. The results of running these two tests, coupled with the results of the direct data access, are shown in Table 3.3:

            Table 3.3. Nonstatic Data Member Access
            ???
            ???????????????????? Optimized?????? Non-optimized

            Direct Access??????? 0.80????????????? 1.42
            Pointer to
            ?? Bound Member????? 0.80????????????? 3.04
            ?
            Pointer to
            ?? Data Member
            ????? CC???????????? 0.80????????????? 5.34
            ????? NCC??????????? 4.04????????????? 5.34


            The non-optimized results conform to expectations. That is, the addition of one indirection per member access through the bound pointer more than doubles the execution time. The pointer-to-member access again nearly doubles the execution time. The binding of the pointer to data member to the class object requires the addition of the offset minus 1 to the address of the object. More important, of course, the optimizer is able to bring the performance of all three access strategies into conformance, except the anomalous behavior of the NCC optimizer. (It is interesting to note here that the appalling performance of the NCC executable under optimization reflects a poor optimization of the generated assembly code and not an attribute of the source-level C++ code. An examination of the generated non-optimized assembly for both CC and NCC showed the two outputs to be identical.)

            The next set of tests looks at the impact of inheritance on the performance of pointers to data members. In the first case, the independent Point class is redesigned into a three-level single inheritance hierarchy with one coordinate value as a member of each class:

            class Point { ... }; // float x;
            class Point2d : public Point?? { ... }; // float y;
            class Point3d : public Point2d { ... }; // float z;
            The next representation retains the three-level single inheritance hierarchy but introduces one level of virtual inheritance: the Point2d class is virtually derived from Point. As a result, each access of Point::x is now accessing a virtual base class data member. Then, more out of curiosity than need, the final representation added a second level of virtual inheritance, that of Point3d being virtually derived from Point2d. Table 3.4 shows the results. (Note: The poor performance of the NCC optimizer was consistent across the tests, so I've left it off the listing.)

            Table 3.4. Pointer to Data Member Access
            ???
            ???????????????????? Optimized?? %?? Non-optimized
            ?
            No Inheritance?????? 0.80????????????? 5.34
            SI (3 levels)??????? 0.80????????????? 5.34
            VI (1 level)???????? 1.60????????????? 5.44
            VI (2 level)???????? 2.14????????????? 5.51
            ?
            SI:? Single Inheritance?????? VI:? Virtual Inheritance


            Because inherited data members are stored directly within the class object, the introduction of inheritance does not affect the performance of the code at all. The major impact of introducing virtual inheritance is to impede the effectiveness of the optimizer. Why? In these two implementations, each level of virtual inheritance introduces an additional level of indirection. Under both implementations, each access of Point::x, such as

            pB.*bx
            is translated into
            &pB->__vbcPoint + ( bx - 1 )

            rather than the more direct
            &pB + ( bx - 1 )

            The additional indirection reduced the ability of the optimizer to move all the processing into registers.

            posted on 2006-11-23 20:23 Jerry Cat 閱讀(1172) 評論(0)  編輯 收藏 引用

            <2006年11月>
            2930311234
            567891011
            12131415161718
            19202122232425
            262728293012
            3456789

            常用鏈接

            留言簿(7)

            隨筆檔案

            最新隨筆

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            avtt天堂网久久精品| 99久久做夜夜爱天天做精品| 国内精品伊人久久久久AV影院| 无码人妻精品一区二区三区久久 | 久久水蜜桃亚洲av无码精品麻豆| 久久精品国产99久久久古代| 日韩精品久久无码人妻中文字幕| 久久99国产精品99久久| 久久亚洲精品无码观看不卡| 久久九九兔免费精品6| 精品久久8x国产免费观看| 丁香五月综合久久激情| 亚洲乱码中文字幕久久孕妇黑人| 国产精品无码久久久久久| 性做久久久久久免费观看| 久久国产乱子伦免费精品| 久久男人AV资源网站| 精品午夜久久福利大片| 国产A级毛片久久久精品毛片| 久久精品国产91久久综合麻豆自制| 伊人色综合九久久天天蜜桃| 国内精品欧美久久精品| 久久精品国产69国产精品亚洲| 久久丫忘忧草产品| 久久涩综合| 中文字幕亚洲综合久久| 精品无码久久久久国产| 中文字幕无码免费久久| 中文字幕无码久久精品青草| 91精品国产91久久久久久蜜臀| 久久久亚洲欧洲日产国码aⅴ| 亚洲国产精品无码久久九九 | 亚洲乱码日产精品a级毛片久久| 久久精品这里热有精品| 久久婷婷五月综合色奶水99啪| 久久久久久久女国产乱让韩| 女同久久| 亚洲精品国产字幕久久不卡| 77777亚洲午夜久久多人| 中文字幕热久久久久久久| 久久精品国产久精国产果冻传媒|