There is no advantage here over just abort()'ing directly after failing to create the GL3 context. The OS is going to deal with freeing all your resources when you abort(), so why bother unwinding all the way to main?
There's nothing wrong with doing a clean exit, and there is nothing wrong with code that is clear and concise. The mere fact that the OS will close your handles and such isn't really an excuse. If it was, you'd just do a
*(void*)0; when the user selects "quit" from the menu. That will certainly quit the program, too :-)
But more importantly, you're (deliberately, as I must assume) neglecting that printing out a one-line-message followed by
abort is not what exceptions are meant for (even though this is what most people do anyway, almost all the time).
Aborting the process is the
absolutely last thing you do, if there's no other options. If rudely killing the process when "something bad" happens is your intent, you can indeed just as well call
abort. You'll have 8 keys less to type for the same effect.
Exceptions are for cases where you might have a chance of recovering in some way, or where you might at least have a chance of crashing less hard.
Such as trying another thing if the first (which is expected to work most of the time) fails. Or, for example, a program that has been writing to disk might want to exit cleanly even in the presence of a problem that prevents it from continuing -- instead of killing the process and forfeiting the data in the buffers. Or, it might want to delete all open (writeable) files under the assumption that they are possibly incomplete/unusable, and such files shouldn't stay around. The handler doesn't even need to know what went wrong or where, it doesn't care in this case.
This could of course also be done without exceptions, but not as cleanly, in one place, with a single handler for a hundred possible reasons.
woe betide the programmer who forgets to write said handler (or doesn't know he needs to)...
True, but... the same is true for return codes, except for one tiny detail. If someone doesn't check return codes, it "works" and doesn't work, and nobody can tell why. Or, it works for a while and then crashes at a completely unrelated occasion because some pointer is NULL. Or, it simply corrupts data and you never find out until 2 months after shipping when your boss starts yelling at you. Or, something different.
If someone forgets to handle exceptions, the application will be terminated with a human-readable message that is (hopefully) somewhat meaninful, at least to the guy who wrote the code. It
will not go unnoticed.
This isn't an exceptional situation, it's an anticipated and error-checked situation. This isn't an exceptional situation either, it's an anticipated and handled error situation.
Both are true, and both are silly arguments against exceptions. Not the code that you write is exceptional,
but the occurrance of an exception, that is, the condition failing.
Exceptions assume that your code and the data is "generally OK" and it "generally works", most of the time, and they are a way of still ensuring that something is done in the exceptional case when that's not true (and, without making the code unreadable, though what's "unreadable" and what is not is probably a very personal matter of taste, you might not agree on that part).
It would be really nice if I magically didn't have to think about errors ever again, by flipping the "compile with exceptions" switch. But of course, you still have to write code that anticipates (and handles) failure.