-1

A picture of memory output debugging stuff

the W, S, G are W( base class ) S( derived from base W ), G( derived from base W ). S has two extra floats that W doesn't, G has a bool W doesn't. the numbers following the letters is just sizeof( W/S/G ).

the ants are made like so

W* _ants = new S[ 6 ];

and the function giving the problem is called like so

for( int i = 0; i < 6; i++ )
{
    std::cout << "Ant " << i << ": " << &_ants[ i ] << std::endl;
    _ants[ i ].update();
}

update is a non-virtual method from W, though it does call a virtual method within it. I have tried removing the virtual method but it still crashes.

I'm pretty sure the problem is that the array is trying to allocate for W but since it is 8 bytes smaller than S _ants goes off track at 1 iteration, is there anyway I can get _ants to allocate the correct amount per iteration without trying to change it to S* or at least keep it on track somehow?

  • 1
    Your question doesn't even contain a minimal example. I guess that you are slicing/truncating an object, like assinging a derived instance to a base instance. – Ulrich Eckhardt Oct 16 '15 at 17:43
  • I think it's not slicing/truncating since the ants are being made at a value 2 bytes away from where they are being stored. plus the slicing should fix this problem since I'm still treating the _ants as an array of W. Any more information I could give that would be helpful? I try to post the minimum amount of information in attempt to not over-saturate the question with code. – Garrett Hale Oct 16 '15 at 17:46
  • This question may be useful for you: http://stackoverflow.com/questions/7203590/array-of-polymorphic-base-class-objects-initialized-with-child-class-objects – Andrey Nasonov Oct 16 '15 at 17:50
  • Well, you have an answer below. Anyhow, you are not supposed to post all your code, but an extract that contains the minimum amount of code that is required to reproduce the issue, see the guidelines. Next time, do that even before posting questions here, because it helps you solve the problem yourself. – Ulrich Eckhardt Oct 16 '15 at 17:51
  • besides the .h files of all the variables and methods included in the class, which I doubt would actually be that useful I don't see what else I could post to help. Either way I'll try to keep that in mind. – Garrett Hale Oct 16 '15 at 17:58

3 Answers3

1

This is one of the best reasons you should not use C-style arrays in C++ unless you have no choice. The language can't easily distinguish between a pointer to a single instance and a pointer to an array, so it cannot detect when you use the latter in an instance where only the former is legal.

W* _ants = new S[ 6 ];

This is setting you up to fail. The array of 6 S objects lays them out in memory sizeof(S) bytes, plus padding, apart.

So what's going on here? The type on the right is S*. While here it points to an array, the conversion to W* is allowed because the same type could point to a single object. While converting a pointer to a single instance of a derived type to a pointer to its base is perfectly legal, it is impossible to do the same thing for a pointer to an array. The memory layout is just not the same.

_ants[ i ].update();

And then here you fail. This adds i * sizeof(W) bytes to _ants, which does not match the layout.

See here for more information.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

Your problem is that your memory is not going to line up. When you do

W* _ants = new S[ 6 ];

You now allocated enough space for 6 S but you are using a pointer of type W to traverse it. Since W is smaller than S after the first iterator you will point to memory that is the end of the first S and part of the second S

If you want to store 6 S* in a W* container then I suggest you use a std::vector and do something like:

std::vector<W*> data;
for (int i = 0; i < some_number; i++)
{
    data.push_back(new S());
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

Your reasoning is correct for why it's misaligned. You shouldn't use arrays polymorphically. Instead of having an array of Ws, use could use an array of W*s. This is one way to work around this problem:

W** _ants = new W*[6];
for( int i = 0; i < 6; i++ )
  ants[i] = new S(...);
}
//...
for( int i = 0; i < 6; i++ )
{
    _ants[ i ]->update();
}
Mike Precup
  • 4,148
  • 21
  • 41
  • I thought about doing this but I'm a little sheepish when it comes to pointers to pointers, I do find this nicer than using vectors but that just comes down to personal preference I guess. – Garrett Hale Oct 16 '15 at 18:00