Jump to content
  • Advertisement
Sign in to follow this  
PureSnowX

Make sure stack-unwinding happens

This topic is 2339 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'v recently hit into a bump with my coding, mostly C++ is a very error prone language, a lot of undefined things can happen when something fails which can lead into memory leaks.

I'n my "Map" class constructor I have a method that loads map data from a file, it returns true or false depending if it failed or not.

Map::Map( const std::string filePath, sf::Texture* tileset )
{
if( !loadDataFromFile( filePath ) )
{
tileMatrix = NULL;
}
this->tileset = tileset;
}

The tileMatrix is a 2D matrix that is dynamically allocated when loading a map, and the values are inserted into it.
My question started of, what should I do if the function actually fails? Then the map allocated contains no actual data to display, and when it reaches the draw of my program, it will crash due to trying to access a NULL pointer and when it crashes the stack-unwinding will not happen thus not de-allocate all my memory allocated. How do most

I want to exit the program when map loading fails and de-allocate all my memory, this happens quite deep into the program flow that it's going to be hackish for it to reach the main's return.

How do people deal with these kinds of loading? Should I make an method in the map-class that returns true or false, like:

/* Somewhere inside my game-class loading */
void Game::run()
{
maps.push_back(new map("map001.map") );
maps.push_back(new map("map002.map") );
maps.push_back(new map("map003.map") );
maps.push_back(new map("map004.map") );
maps.push_back(new map("map005.map") );
for(int i = 0; i < maps.lenght - 1; i++)
if(!maps.initialized())
{
std::cout << "A map failed to load correctly" << std::endl;
return;
}
/* Game Loop, and other Code */
}

Or is their a more preferred way to deal with these kinds of errors deep inside the code?
Does this work?

int main()
{
try
{
Game game("Awesome Game");
game.run();
}
catch(...)
{
return -1;
}
return 0;
}

Can I do "throw "Couldn't load map" << std::endl;" inside the Map-class constructor? Would it catch it even if it's not directly called by the Game class but a class within the game class? Will it trigger stack-unwinding? Edited by Moonkis

Share this post


Link to post
Share on other sites
Advertisement
When you throw, you must manually unwind the stack yourself, think of it this way. (The stacks will be terminated, but anything with Memory you manually allocated will exist in the Heap still) - however local variables that aren't using the new keyword (non-pointer essentially) will be cleaned up.


Function 1
--- Function 2
--- Function 3
--- Function 4

If you throw an Exception in Function 4, and Function 1 has the catch, any Pointers in Function 2-3 will NOT be cleaned, so to do this you can actually rethrow the Exception,


try {
... do stuff ...
} catch(...) {
...clean memory...
throw;
}


And you must transverse up in Function 2 and 3 with the same try { } catch blocks. But that seems like a major hassle doesn't it?

Of course, you should probably treat it more as a design issue. I would consider it a bad design to have an exception be thrown so deep in the code, and only have a very thin veil handling the error.

You could try use smart_pointers, they clean themself up when out of scope.


*edited to add code tags


Edit: Also considering your code, as maps is a global variable, your particular instances of new map exist outside of the Stack-Heap as their being put into maps vector, you could possibly rewrite maps into a class and just simply have a memory clean up in the deconstructor of maps. Unless I'm misreading it, and maps is an actual member of Game class, then clean it up in your Game deconstructor.

I'm new at this, trying my best to learn more by forum discussions lol Edited by dimitri.adamou

Share this post


Link to post
Share on other sites
If you get into exceptions, also make sure to study RAII ("resource acquisition is initialization"). It is central to exception safe code, and alleviates basically all the headaches described in the preceding post.

Share this post


Link to post
Share on other sites
If you decide not to go with exceptions I would not load the data inside the constructor but instead make a separate function that returns whether it succeeded or not.

Share this post


Link to post
Share on other sites

If you get into exceptions, also make sure to study RAII ("resource acquisition is initialization"). It is central to exception safe code, and alleviates basically all the headaches described in the preceding post.

I'll be happy to let you know I use RAll as much as possible, even prefer references over pointers any day but sometimes I need them pointers. Maybe I should use smart pointers for this case, but I'd rather solve it in a nice way without exceptions :)



If you decide not to go with exceptions I would not load the data inside the constructor but instead make a separate function that returns whether it succeeded or not.

Well the constructor calls loadDataFromFile(); which does return true or false and is a public function, I guess I could use it but I really like object-creation and map-loading one call i.e from the constructor if possible WITH proper error-handling?



Edit: Also considering your code, as maps is a global variable, your particular instances of new map exist outside of the Stack-Heap as their being put into maps vector, you could possibly rewrite maps into a class and just simply have a memory clean up in the deconstructor of maps. Unless I'm misreading it, and maps is an actual member of Game class, then clean it up in your Game deconstructor.

I'm new at this, trying my best to learn more by forum discussions lol

Maps is a vector/ inside game that hold map-objects.
Apart from all that I think you contributed, but really is it considered bad design to have exceptions thrown deep into the code? Can't exceptions happen in a lot of places?
I surrounded my main into a try-catch(std::exception& excptn) that deals with unhandled exceptions ( like if new fails due to bad_alloc that I actually unwind the stack and close it properly? ) of course I will put try-catch on places that needs it but I like to have a safety net of some sort?

Share this post


Link to post
Share on other sites

[quote name='dimitri.adamou' timestamp='1342654416' post='4960716']
Edit: Also considering your code, as maps is a global variable, your particular instances of new map exist outside of the Stack-Heap as their being put into maps vector, you could possibly rewrite maps into a class and just simply have a memory clean up in the deconstructor of maps. Unless I'm misreading it, and maps is an actual member of Game class, then clean it up in your Game deconstructor.

I'm new at this, trying my best to learn more by forum discussions lol

Maps is a vector/ inside game that hold map-objects.
Apart from all that I think you contributed, but really is it considered bad design to have exceptions thrown deep into the code? Can't exceptions happen in a lot of places?
I surrounded my main into a try-catch(std::exception& excptn) that deals with unhandled exceptions ( like if new fails due to bad_alloc that I actually unwind the stack and close it properly? ) of course I will put try-catch on places that needs it but I like to have a safety net of some sort?
[/quote]

My bad, I ment that I consider it a bad design choice to have a deep-nested exception being thrown and caught by something so far up the heirarchy [based on what I was saying... I just sort of ran off! lol]. Like say Stack 4 raising an exception where Stack 1 would catch it. It can cause unpredictable results, exceptions are just that - an exception. Personally I prefer the exception to resolve itself within the stack immediately

Maybe you can reapproach your map loading design and create a Factory Class? Let the Factory Class determine if a Map is fit to be created for loading or not, and if it is - it'll return either a nullptr or a map object Edited by dimitri.adamou

Share this post


Link to post
Share on other sites

My bad, I ment that I consider it a bad design choice to have a deep-nested exception being thrown and caught by something so far up the heirarchy [based on what I was saying... I just sort of ran off! lol]. Like say Stack 4 raising an exception where Stack 1 would catch it. It can cause unpredictable results, exceptions are just that - an exception. Personally I prefer the exception to resolve itself within the stack immediately

An exception should be used when you encounter an error situation that you do not know how to resolve immediately. If you know how to resolve it within the stack immediately, it is not appropriate to throw an exception to handle it, you should just handle it.

So, if you're using exceptions properly, they're more likely to be handled farther up in the stack. I have no qualms about throwing exceptions where I need to but I rarely have a catch clause outside of main(). Not never, but quite rarely. A graceful shutdown with some sort of explanatory error message in a log is always better than a mystery segfault.

Share this post


Link to post
Share on other sites

My bad, I ment that I consider it a bad design choice to have a deep-nested exception being thrown and caught by something so far up the heirarchy [based on what I was saying... I just sort of ran off! lol]. Like say Stack 4 raising an exception where Stack 1 would catch it. It can cause unpredictable results, exceptions are just that - an exception. Personally I prefer the exception to resolve itself within the stack immediately

Maybe you can reapproach your map loading design and create a Factory Class? Let the Factory Class determine if a Map is fit to be created for loading or not, and if it is - it'll return either a nullptr or a map object

Could you please provide a few links to this maybe of some good examples ( Preferably in C++ )? It sounds interesting!


An exception should be used when you encounter an error situation that you do not know how to resolve immediately. If you know how to resolve it within the stack immediately, it is not appropriate to throw an exception to handle it, you should just handle it.

So, if you're using exceptions properly, they're more likely to be handled farther up in the stack. I have no qualms about throwing exceptions where I need to but I rarely have a catch clause outside of main(). Not never, but quite rarely. A graceful shutdown with some sort of explanatory error message in a log is always better than a mystery segfault.


I'll think I might be able to use an array of unique_ptr<Map> for the vector that holds the maps, using a try-catch() statement when loading all the files, causing the program to gracefully shut down and make stack-unwind to release all resources.

This part of the code is not required to be explicitly fast anyway. Though it could be handled in simpler way.
I notice now that file-loading or resource loading inside the constructor is generally a "bad" way seeing as you can't really handle the error gracefully ( Sure you might have some error-code but you will have a fully constructed object with "null" or "default" values ).

I would like to have something similar to the stream-class:

ifstream is("filetoopen.txt");
if(!is)
return false;


this I would like to implement into the map-class:

Map map("FileToLoad.txt");
if(!map)
return false;

What operator would I override for this behavior? Is it more standard to make it throw an exception? I'm guessing ifstream throws an exception when failing to load a file?
Is it just better to let the program crash horribly? Leaving memory behind? Before crashing, print to a log-file?

I guess I'm just not in love with having the program leave memory behind without trying to de-allocate it.
Also do YOU have a catch inside of main?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!