#1 Members - Reputation: 609
Posted 08 October 2012 - 01:22 PM
Or is safer to make explicit destructor calls before calling exit(0)?
#2 Members - Reputation: 1588
Posted 08 October 2012 - 01:32 PM
While the OS will clean up all dynamically allocated memory, it is a *very* good idea to free up all resources by calling delete for each object you new, delete[] for each array you new[], free() for everything you malloc() and so on. This is because (unless your program is very very simple) you don't know how many times different objects are allocated and removed, and you'll easily have a million memory leaks at runtime, and your app can run out of memory easily. Also, there are other types of resources that might not be automatically freed by the OS (sockets, file handles, temporary allocated disk space, pipes, mutexes, other Win32 API handles, etc.), or their release may be delayed (in particular, abandoned sockets will linger and go to unusable state for security reasons).
Some argue that calling exit(0) can be better instead of manually tearing down all application objects, but unless you're 500% sure that nothing described above applies in your case, I really really recommend avoiding it. Plus, not freeing up memory makes it impossible to debug whether you have memory leaks in the first place, e.g. you can't use the amazing VLD tool then.
#3 Marketplace Seller - Reputation: 8925
Posted 08 October 2012 - 01:34 PM
Reasons:
- What if you later use an OS that doesn't do that? For example, your program running on an embedded system?
- If you make it a habit, your program can memory leak if it runs for a long time (continually new-ing, but not delete-ing), which is one of the signs of a bad programmer.
- If I had a company (which I don't) and you were applying for a job (which you aren't), I wouldn't want to hire you if I knew you did that. I'd consider it laziness, "Let someone else handle it! I can't be bothered to do my job properly, so I'll take shortcuts" <--- This is the impression I'd get while interviewing you.
- Not all program resources are properly cleaned up by the OS. Some specific types of resources are made to hold their state beyond the program's lifetime.
- You might as well be consistently correct, rather than relying on things which may only be correct 99% of the time - or 1% of the time you'll be bitten.
But that's all besides the point! Instead of trusting the OS to maybe clean up the data, and instead of trusting yourself to remember every single time, why not let C++ free the memory for you? With modern C++, you should use smart pointers (either standard C++11, or else the Boost versions), and let C++ handle all your dynamic memory for you. Let it handle your 'new' calls (using std::make_shared() or similar), and let it handle all your 'delete' calls (using the smart pointer destructors).
But ofcourse the best memory management is the stack, which should be your default choice.
Edited by Servant of the Lord, 08 October 2012 - 01:43 PM.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#4 Members - Reputation: 609
Posted 08 October 2012 - 01:57 PM
This is what my game main loop exactly looks like
[source lang="cpp"] Game game;while(window.isOpen()){ sf::Event event; while(window.pollEvent(event)) { if(event.type==sf::Event::Closed) { game.~Game();//so I should do this...? exit(0); } } window.clear(); game.handleEvent(); game.update(); game.draw(window); window.display();}[/source]
Edited by lride, 08 October 2012 - 01:58 PM.
#5 Marketplace Seller - Reputation: 8925
Posted 08 October 2012 - 02:02 PM
[Edit:] Apparently exit() doesn't unwind the stack!
Also, 'Game' is not a singleton in the example you gave above. Just because there is only one, doesn't mean it's a singleton. A singleton is something different (and something you want to avoid).
However, exit() isn't what you probably want to use there (
I like my code to exit properly out of the int main() (or whatever entry point) function by a good return call.
Edited by Servant of the Lord, 08 October 2012 - 02:13 PM.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#7 Marketplace Seller - Reputation: 8925
Posted 08 October 2012 - 02:21 PM
But unfortunately, exit() apparently doesn't unwind the stack like I initially thought.
Edited by Servant of the Lord, 08 October 2012 - 02:22 PM.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#8 Members - Reputation: 609
Posted 08 October 2012 - 02:25 PM
Yes it would try to destruct twice and have odd side effects - hopefully crashing your program, but possibly not crashing but wrecking other parts of your progam in unpredictable ways.
But unfortunately, exit() apparently doesn't unwind the stack like I initially thought.
if it exit() doesn't unwind the stack, why would the destructor be called?
http://stackoverflow...om-being-called
exit() is more complicated than I thought... This is what it says in the standard...
Calling the function void exit(int); declared in <cstdlib> (18.3) terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration (12.4). If exit is called to end a program during the destruction of an object with static storage duration, the program has undefined behavior.
I have no idea what it means by
If exit is called to end a program during the destruction of an object with static storage duration, the program has undefined behavior.
(say I called exit(0). Then my program has undefined behavior while returning 0. )
EDIT:
It turns out that return 0 is more favorable than exit(0)
http://stackoverflow.com/questions/461449/return-statement-vs-exit-in-main
Edited by lride, 08 October 2012 - 02:47 PM.
#9 Moderators - Reputation: 5033
Posted 08 October 2012 - 03:13 PM
It means if you write code like this, all bets are off:
// Don't do this!
struct Bad {
~Bad() {
std::ofstream out("fin.txt");
if(!out) {
exit(1);
}
// Write buffer to out...
}
void log(const std::string &message) {
buffer.push_back(message);
}
std::vector<std::string> buffer;
};
int main()
{
static Bad bad;
bad.log("Hello, world");
// More logic
}
The language makes no guarantees about what might happen.Note that the intent behind the above code is another example of why immediately terminating the process can be a poor habit. Imagine a call to exit where the "main logic" is - while the OS will correctly clean up all the resources it is aware of, it cannot know that the contents of "buffer" should have been saved to a file.
#10 Moderators - Reputation: 6623
Posted 08 October 2012 - 03:26 PM
#11 Marketplace Seller - Reputation: 8925
Posted 08 October 2012 - 07:35 PM
It wouldn't in this case, because exit() doesn't unwind the stack. If it did unwind the stack, the class would be destructed twice.
Yes it would try to destruct twice and have odd side effects - hopefully crashing your program, but possibly not crashing but wrecking other parts of your progam in unpredictable ways.
But unfortunately, exit() apparently doesn't unwind the stack like I initially thought.
if it exit() doesn't unwind the stack, why would the destructor be called?
Most certainly.exit() is more complicated than I thought...
Definitely - it's always preferable to do things "the regular way" then to do things some other way that has a bunch of asterisks all over it.It turns out that return 0 is more favorable than exit(0)
http://stackoverflow...vs-exit-in-main
Functions should return by calling 'return' or in void functions, it's also fine to just reach the end of the function though you can still call 'return' if you like). int main() is no exception. main() should exit by calling "return 0" or "return EXIT_SUCCESS" on success, or return something else on failure (preferably EXIT_FAILURE).
If you enter a function, you should exit the function properly by returning. If a problem occurs, then it's permissible to exit a function through some other method (like throwing an exception, or terminating, or etc...), but each "other method" has their own select group of things you need to be aware of when using it (whether it be throwing an exception, or calling something like exit()).
Doing anything abnormal should be avoided, except when you have to when something goes wrong. Exiting a function through any method except returning is abnormal. Even when something does go wrong, try to exit normally (or recover) if you can.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal






