Jump to content

  • Log In with Google      Sign In   
  • Create Account


Exiting a game by closing window.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 lride   Members   -  Reputation: 633

Like
0Likes
Like

Posted 08 October 2012 - 01:22 PM

Can I just call exit(0) without making explicit destructor calls of objects since all dynamically allocated memory is supposed to be freed when application exits?
Or is safer to make explicit destructor calls before calling exit(0)?
An invisible text.

Sponsor:

#2 clb   Members   -  Reputation: 1777

Like
4Likes
Like

Posted 08 October 2012 - 01:32 PM

If this is C++, you never explicitly call destructors of objects, unless you have allocated them using placement new (which I doubt in this case).

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.
Me+PC=clb.demon.fi | C++ Math and Geometry library: MathGeoLib, test it live! | C++ Game Networking: kNet | 2D Bin Packing: RectangleBinPack | Use gcc/clang/emcc from VS: vs-tool | Resume+Portfolio | gfxapi, test it live!

#3 Servant of the Lord   Crossbones+   -  Reputation: 17060

Like
3Likes
Like

Posted 08 October 2012 - 01:34 PM

You could, but it's a very bad behavior to get into.

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.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

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.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#4 lride   Members   -  Reputation: 633

Like
0Likes
Like

Posted 08 October 2012 - 01:57 PM

I have a singleton class Game and the destructor of the Game class calls delete for every game objects.
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.

An invisible text.

#5 Servant of the Lord   Crossbones+   -  Reputation: 17060

Like
2Likes
Like

Posted 08 October 2012 - 02:02 PM

No. The destructor should not be explicitly called.
Because 'game' is on the stack, exit() when called will free everything on the stack (I think? I don't generally use exit()), and everything freed will call their own destructors.
[Edit:] Apparently exit() doesn't unwind the stack! Posted Image Another reason to avoid using it in your situation.

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 (though it'd work). Instead, why not just call window.close() when you get sf::Event::Closed, like the SFML documentation suggests? Alternatively, you could have your own bool instead of window.isOpen(), and set the bool to false when you get sf::Event::Closed, though the result is the same.

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.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

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.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#6 lride   Members   -  Reputation: 633

Like
0Likes
Like

Posted 08 October 2012 - 02:10 PM

If I had called the destructor explicitly, will the destructor be called again when game goes out of stack?(calling delete twice on the same memory location)
An invisible text.

#7 Servant of the Lord   Crossbones+   -  Reputation: 17060

Like
0Likes
Like

Posted 08 October 2012 - 02:21 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.

Edited by Servant of the Lord, 08 October 2012 - 02:22 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

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.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#8 lride   Members   -  Reputation: 633

Like
0Likes
Like

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.

An invisible text.

#9 rip-off   Moderators   -  Reputation: 7642

Like
2Likes
Like

Posted 08 October 2012 - 03:13 PM

In general, one should only explicitly call a destructor if one also explicitly called the constructor (i.e. via placement new).

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 SiCrane   Moderators   -  Reputation: 9387

Like
2Likes
Like

Posted 08 October 2012 - 03:26 PM

Note that there are some resources that the OS will not clean up, or may not clean up "properly". For Windows, an example of the former is ATOMs allocated by the GlobalAddAtom() function, which is explicitly noted as not being cleaned up by application exit in the API documentation. An example of a clean up that might not do what you expect is are Windows semaphore objects, whose handles are automatically closed by process exit, but process exit doesn't affect semaphore count. So if you've got other processes waiting for you to finish using that semaphore, they might wait forever.

#11 Servant of the Lord   Crossbones+   -  Reputation: 17060

Like
2Likes
Like

Posted 08 October 2012 - 07:35 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?

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.

exit() is more complicated than I thought...

Most certainly.

It turns out that return 0 is more favorable than exit(0)
http://stackoverflow...vs-exit-in-main

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.

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.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

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.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS