CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Jul 2005
    Posts
    1,030

    A question regarding array

    Here is the code,
    Code:
    #include <iostream>
    
    using namespace std;
    
    class B
    {
    public:
    	virtual int getValue(){return 1;}
    private:
    	int _x;
    };
    
    class D : public B
    {
    	virtual int getValue() {return 2;}
    private:
    	double _y;
    	int _z;
    	int _w;
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {	
    	B* b = new D[10];
    
    	int diff = &b[2] - &b[1];
    	int x = b[2].getValue();
    	return 0;
    }
    I have two questions here. Actually B's size is 8 bytes and D's size is 24 bytes. First question is why diff is 1 instead of 8? The second question why b[2].getValue() gives access violation exception since b points to a chuck of size 24*10. Thanks.

  2. #2
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: A question regarding array

    Quote Originally Posted by LarryChen View Post
    [...] Actually B's size is 8 bytes and D's size is 24 bytes. First question is why diff is 1 instead of 8?
    This is simply how pointer arithmetic goes (see http://www.cplusplus.com/doc/tutorial/pointers/)...

    The result of the pointer subtraction is expressed in terms of pointed-to object sizes, not bytes. The addition of an integer to a pointer works equivalently, that way being consistent with indexing. Actually, p[n] is just another way to write *(p + n) (but it looks much nicer... ). If you want a result in bytes, cast the pointers to char * (not _TCHAR *, since _TCHAR may have a size of two bytes) first:

    Code:
    	int diff = reinterpret_cast<char *>(&b[2]) - reinterpret_cast<char *>(&b[1]);
    ... or simply multiply the result by sizeof(B).

    The second question why b[2].getValue() gives access violation exception since b points to a chuck of size 24*10. Thanks.
    That's somewhat related to the above: You're indexing an array of B objects, and that's all the compiler knows at that point. So it ignores the fact that the array actually is comprised of D objects which are of different size. So it bases its address calculation on the size of B and the result, although it actually points to memory you own, points to anything but (the start of) a valid oject of any type. IIRC what's going on here is called object slicing, and it's definitely evil.

    I can envision a haphazard hack to force something like that to work, involving a virtual function by which a given object can return its own concrete size. But due to the variable object size, you can't index such a data structure, so it would rather resemble a linked list than an array, and that's just one of several weird complications such an approach would most certainly provoke. Much better would be to simply take the straightforward and common approach of using an array (or std::vector) of pointers rather than object instances (like any experienced programmer most certainly would, BTW).
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #3
    Join Date
    Apr 1999
    Posts
    27,449

    Re: A question regarding array

    The second question why b[2].getValue() gives access violation exception since b points to a chuck of size 24*10. Thanks.
    But a B is not a D. What is the compiler supposed to do with b[2]? The compiler has no idea that it is actually pointing to an array of D objects, so it will just add 2 * sizeof(B) to the address of b, and that is where you're pointing.

    Any time you see this:
    Code:
    B* b = new D[10];
    and D happens to be derived from B, you can almost guarantee that the code that uses B is faulty. As good as it looks, there is absolutely no polymorphism going on in that line -- it's a mistake. The reason why it compiles is that new D [10] returns a D*, and a D* is compatible with a B*. However using that b variable as if it's a D -- well you just shot yourself in the foot.

    Regards,

    Paul McKenzie

  4. #4
    Join Date
    Jul 2005
    Posts
    1,030

    Re: A question regarding array

    Quote Originally Posted by Eri523 View Post
    This is simply how pointer arithmetic goes (see http://www.cplusplus.com/doc/tutorial/pointers/)...

    The result of the pointer subtraction is expressed in terms of pointed-to object sizes, not bytes. The addition of an integer to a pointer works equivalently, that way being consistent with indexing. Actually, p[n] is just another way to write *(p + n) (but it looks much nicer... ). If you want a result in bytes, cast the pointers to char * (not _TCHAR *, since _TCHAR may have a size of two bytes) first:

    Code:
    	int diff = reinterpret_cast<char *>(&b[2]) - reinterpret_cast<char *>(&b[1]);
    ... or simply multiply the result by sizeof(B).



    That's somewhat related to the above: You're indexing an array of B objects, and that's all the compiler knows at that point. So it ignores the fact that the array actually is comprised of D objects which are of different size. So it bases its address calculation on the size of B and the result, although it actually points to memory you own, points to anything but (the start of) a valid oject of any type. IIRC what's going on here is called object slicing, and it's definitely evil.

    I can envision a haphazard hack to force something like that to work, involving a virtual function by which a given object can return its own concrete size. But due to the variable object size, you can't index such a data structure, so it would rather resemble a linked list than an array, and that's just one of several weird complications such an approach would most certainly provoke. Much better would be to simply take the straightforward and common approach of using an array (or std::vector) of pointers rather than object instances (like any experienced programmer most certainly would, BTW).
    It is a shame I didn't know that. Thanks a lot for the tutorial.

  5. #5
    Join Date
    Jul 2005
    Posts
    1,030

    Re: A question regarding array

    Quote Originally Posted by Paul McKenzie View Post
    But a B is not a D. What is the compiler supposed to do with b[2]? The compiler has no idea that it is actually pointing to an array of D objects, so it will just add 2 * sizeof(B) to the address of b, and that is where you're pointing.

    Any time you see this:
    Code:
    B* b = new D[10];
    and D happens to be derived from B, you can almost guarantee that the code that uses B is faulty. As good as it looks, there is absolutely no polymorphism going on in that line -- it's a mistake. The reason why it compiles is that new D [10] returns a D*, and a D* is compatible with a B*. However using that b variable as if it's a D -- well you just shot yourself in the foot.

    Regards,

    Paul McKenzie
    Thanks for the clarification!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured