1

I'm decent at C++, but I may have missed some nuance that applies here. Or maybe I completely missed a giant concept, I have no idea. My program was instantly crashing ("blah.exe is not responding") about 1/5 times it was run (other times it ran completely fine) and I tracked the problem down to a constructor for a world class that was called once in the beginning of the main function. Here is the code (in the constructor) that causes the problem:

int ii;
for(ii=0;ii<=255;ii++)
{
    cout<<"ent "<<ii<<endl;
    entity_list[ii]=NULL;
}
for(ii=0;ii<=255;ii++)
{
    cout<<"sec "<<ii<<endl;
    sector_list[ii]=NULL;
}
entity_list[0] = new Entity(0,0);
entity_list[0]->_world = this;

Specifically the second for loop. The cout references are new for the sake of telling where it is having trouble. It would print the entire "ent 1" to "ent 255" and then "sec 1" to "sec 255" and then crash right after, as if it was going for a 257th run through of the second for loop. I set the second for loop to go until "ii<=254" which stopped all crashes. Does C++ code tend to "overshoot" for loops or something? What is causing it to crash at this specific loop seemingly at random?

By the way, entity_list and sector_list point to classes called Entity and Sector, respectively, but they are not constructing anything so I didn't think it would be relevant. I also have a forward declaration for the Entity class in a header for this, but since none were being constructed I didn't think it was relevant either.

cccc
  • 47
  • 4
  • I'd think it was the `Entity(int,int)` constructor call or the assignment of `entity_list[0]->_world`, and you got a superfluous space in the inc statement of the second for – ratchet freak Dec 01 '11 at 02:44
  • 1
    did you step thru it in a debugger? You might want to add a print statement to between the lines after the two for loops (in case the crash is after the for loops). And you don't show your entity_list/sector_list array declarations so its unclear if you've allocated enough space. Also it's a bit more common to make the stopping case be like ii<256 rather than ii<=255 (but they amount to the same). – Kevin Dec 01 '11 at 02:47
  • @ratchetfreak I saw that, was accidentally put in when I posted it. –  Dec 01 '11 at 02:48
  • Note there are better ways of zeroing memory. If the arrays are defined with constant size, use [empty brackets](http://stackoverflow.com/questions/1920430) to initialize the array (`Entity *entity_list[ENTITY_LIST_SIZE] = {};`). If the arrays are dynamically allocated with `new`, use [parentheses](http://stackoverflow.com/questions/7186274/) at the end of the initializer expression (`new Entity*[n]()`). Either will value-initialize the array items (which, for pointers, means they will be zero-initialized). Better still, use STL data structures, such as `std::vector` or `std::deque`. – outis Dec 01 '11 at 05:10
  • Why not use std::list instead of arrays? http://www.parashift.com/c++-faq-lite/containers.html#faq-34.1 – Sardathrion - against SE abuse Dec 01 '11 at 07:45

2 Answers2

9

You are going beyond the bounds of your array.

Based on your comment in Charles' answer, you stated:

I just declared them in the world class as entity_list[255] and sector_list[255]

And therein lies your problem. By declaring them to have 255 elements, that means you can only access elements a[0] through a[254] (If you count them up, you'll find that that is 255 elements. If index a[255] existed, then it would mean that there were 256 elements).


Now for the question: Why did it act so erratically when you accessed an element outside of the bounds of the array?

The reason is because accessing elements outside of the bounds of the array is undefined behavior in C++. I can't tell you what it should do, because it has been intentionally left undefined (don't ask me why--maybe someone who knows can comment?).

What this means is that the results will be sporadic and unpredictable, especially when you run it on different machines.

It might work just fine. It might crash. It might delete your hard drive! (this one is unlikely, but doing so wouldn't be a violation of the C++ protocol!)

Bottom line--just because you got a strange or non-existant error message does NOT mean its ok. Just don't do it.

riwalk
  • 14,033
  • 6
  • 51
  • 68
  • Accessing an `array` of `element`s via `array[index]` is going to access `sizeof(element)` bytes at ( address-pointed-to-by-`array` + `index * sizeof(element)`. That part of the behaviour I believe is actually well defined, and carried over by the C legacy. It allows the programmer to pass sub-sets of arrays (i.e. pointer to a single element, not necessarily the first) around, and access neighbouring elements based on other information the program may have available. In this case, use of an STL-style container would at least have the same behaviour each time. – rvalue Dec 01 '11 at 05:12
  • The "undefined behavior when accessing out-of-bound elements" makes sense when you think about all the edge cases: end of allocated memory, x86 segment boundaries, memory that's mapped read-only... - there's just no way that the standard can reasonably define what will happen across all OS'es and CPU's, and still keep performance decent. – MSalters Dec 01 '11 at 14:21
  • @MSalters, I am now wiser. Thank you. – riwalk Dec 01 '11 at 18:03
1

How did you declare entity_list and sector_list? Remember that you are using 0 based indexing, so if you go from ii = 0 to ii <= 255 you need 256 buckets, not 255.

Charles E. Grant
  • 5,771
  • 1
  • 20
  • 21
  • Maybe I am missing something giant then...I have no idea what buckets are, I just declared them in the world class as entity_list[255] and sector_list[255]. –  Dec 01 '11 at 02:54
  • 1
    "buckets" is a programmer slang term for array indices. He's saying that with entity_list[255], you're only allowed to access elements entity_list[0] through entity_list[254]. Writing into entity_list[255] will result in overwriting memory which potentially was being used for other variables. This is almost assuredly the cause of your crash. – Trevor Powell Dec 01 '11 at 03:12
  • @Zdrok: There's your problem. 0..255 is 256 numbers, so your arrays need 256 items, not 255. – Joey Adams Dec 01 '11 at 03:14
  • I thought defining it as [255] allocated from to +255... Oops. Still doesn't explain why it only crashes some of the time, though, or why, when it does crash, it still creates the new Entity, or why it never crashes on entity_list. I just don't get this at all. –  Dec 01 '11 at 03:18
  • 1
    If there are 255 of them, they will be numbered 0 to 254. You could run your loop to i<=254, but it's more usual to say i<255 – Kate Gregory Dec 01 '11 at 03:22
  • Well I changed it to fix that and it doesn't seem to crash any more. I just misunderstood how arrays were initialized. I'm still confused on why it acted so erratically instead of just crashing every time, but I'm glad it works now. Thanks. Also sorry about posting this in the wrong place, I didn't see the description and I feel stupid now. – cccc Dec 01 '11 at 03:31
  • @Zdrok The behavior of a program that accesses an array outside its bounds isn't defined. That is, nothing requires the system to behave in a particular way. It can do *anything*. (One of the things a lot of people don't like about C/C++ is that you can easily write code whose behavior is completely undefined.) – David Schwartz Dec 01 '11 at 05:44