• Segmentation faults
    6 replies, posted
The following code (C++ and SFML) produces segmentation faults when the left mouse button is clicked to spawn a shell (with Turret::Think() called by SpriteManager::Think()): [code]void SpriteManager::Add(Sprite *in_Sprite) { mySprites.push_back(in_Sprite); } void SpriteManager::Think(sf::RenderWindow &App) { std::vector<Sprite*>::iterator it; for(it = mySprites.begin(); it != mySprites.end(); ++it) (**it).Think(App); } void Turret::Think(sf::RenderWindow &App) { const sf::Input &Input = App.GetInput(); if(Input.IsMouseButtonDown(sf::Mouse::Left)) { Shell myShell; SpriteManager::Instance()->Add(&myShell); } } [/code] I assume it's because the size of the vector mySprites is changed whilst being iterated through in SpriteManager::Think(), but storing the sprite in a different vector and processing it after SpriteManager::Think() yields similar results with the following code: [code]void SpriteManager::Add(Sprite *in_Sprite) { myVector.push_back(in_Sprite); } void SpriteManager::Think(sf::RenderWindow &App) { std::vector<Sprite*>::iterator it; for(it = mySprites.begin(); it != mySprites.end(); ++it) (**it).Think(App); for(it = myVector.begin(); it != myVector.end(); ++it) mySprites.push_back(*it); myVector.clear(); }[/code] and error (from the source of SFML?): [code]Program received signal SIGSEGV, Segmentation fault. In sf::Unicode::Text::Text(std::basic_string<unsigned short, std::char_traits<unsigned short>, std::allocator<unsigned short> > const&) () at D:/Programmation/Cpp/SFML/tags/1.5/src/SFML/Graphics/Drawable.cpp:395 ()[/code] How can I fix this/what other method should I use for handling the updating and rendering of projectiles?
I think I see the problem. It is a classic case of adding an object via a pointer to someplace on the [I]stack[/I] so that when you later operate on that object, it is no longer valid. This is something that java users do when they start working with C++ When you depress the left mouse button, you 'create' a shell by instanciating it on the stack (the line "Shell myShell") and then adding a pointer to that shell into the vector of sprite pointers. The problem is, whenever the turret's 'think' function returns, that shell instance is destroyed along with any other variables on the stack frame. But that pointer still exists in the vector, and when the program tries to call the think function on the object it just created (and destroyed), surprise! The function address points to garbage and segfaults. The quick and easy way to fix this is to change [code]Shell myShell;[/code] to [code]Shell* myShell = new Shell();[/code] as this will create the shell on the heap rather than the stack, and won't be destroyed when the think function returns. You just gotta remember to call delete on all the pointers when you are done with them, otherwise you leak memory. [editline]10:59AM[/editline] The less quick and dirty method involves a heavy overhaul of your sprite manager. You must have noticed that with polymorphism, you can't just add derived classes into a container for base classes. It only works for [I]pointers,[/I] and pointers add indirection and require hefty management. Polymorphism just doesn't scale very well to the level of creating a new class type for every single different type of object you want in your game. What I do is I have many different arrays, and objects in the game are referred to by a 'handle' which is just an index into any arbitrary array. I have arrays for physics objects, graphics objects, sound collections, and lua function pointers. There is little polymorphism going on. I don't need it! Each new and separate entity has some form of each of these, and this allows me to make the data for the objects contiguous and tightly packed in memory. (keeps it fast and memory footprint down) I could probably make it even better by interlacing the arrays. But still, I stay away from high-level polymorphism. It isn't flexible enough for my games.
I had thought that the object might be deleted outside of Turret::Think() but wasn't sure how to rectify this - thanks! I had tried using Shell *myShell = new Shell; before, but not in concjunction with using a different vector for adding and processing it after think, and it is now working as expected.
[QUOTE=Cathbadh;17496494]I could probably make it even better by interlacing the arrays.[/QUOTE] Simply out of curiosity, how would you interlace those widely varying types of arrays without creating more overhead and enlarging the memory footprint of the program?
[QUOTE=WiZzArD;17503159]Simply out of curiosity, how would you interlace those widely varying types of arrays without creating more overhead and enlarging the memory footprint of the program?[/QUOTE] Simple! Instead of having arrays of individual things, I have a single array of structs with all the parts of the object in each struct. It is the natural way to think about an array of objects. In memory, it would be exactly like interlacing each of the separate arrays. This may prove beneficial because higher locality means higher cache hit rates. But there's a reason I'm not doing it this way. My threaded system effectively separates the graphics and physics and sounds and all of that into their own separate threads. It helps with locality in this sense to keep arrays around each with their own themes instead of one big array of full entities. [editline]09:45PM[/editline] The arrays are, after all, isomorphic
If the objects contain all of their resources within themselves, it'd be a mess when objects load the same resources commonly though.
[QUOTE=WiZzArD;17508710]If the objects contain all of their resources within themselves, it'd be a mess when objects load the same resources commonly though.[/QUOTE] In that case, we would probably just keep references instead.
Sorry, you need to Log In to post a reply to this thread.