Page 2 of 2

Re: Are you kidding me?

Posted: Fri May 25, 2012 8:08 am
by mattheweston
So my assumption is incorrect? Its the Try...catch that actually causes that behavior instead of the actual error itself?

Re: Are you kidding me?

Posted: Fri May 25, 2012 9:23 am
by Ginto8
mattheweston wrote:So my assumption is incorrect? Its the Try...catch that actually causes that behavior instead of the actual error itself?
Every language has its own idea of exactly how exceptions should work, so C++ doesn't require you to use them. In C, which never had exceptions anyway, developers often indicate error states by returning some error indicator (eg. NULL) if there's an error. Basic C++ behaves similarly.

So in the case of memory allocation, you can check for an out-of-memory (or any other allocation error) in this way:

Code: Select all

// C

int* hurr = malloc(sizeof(int));
if(!hurr) { // if hurr == NULL, something went screwy
    dieInAFire();
}

Code: Select all

// C++

int* hurr = new int;
if(!hurr) { // same basic behavior as C
    dieInAFire();
}

Re: Are you kidding me?

Posted: Fri May 25, 2012 10:09 am
by mattheweston
I can see where this would be beneficial if you had a 1 to 1 ratio of if..else's replacing try...catch blocks, but what if you had several if...elses that would be in a block of code where one try...catch could take care of it? Wouldn't many if..else's be more expensive than one try...catch?

Re: Are you kidding me?

Posted: Fri May 25, 2012 10:55 pm
by Ginto8
mattheweston wrote:I can see where this would be beneficial if you had a 1 to 1 ratio of if..else's replacing try...catch blocks, but what if you had several if...elses that would be in a block of code where one try...catch could take care of it? Wouldn't many if..else's be more expensive than one try...catch?
Absolutely not. Since conditionals are really the driving force behind any program, CPUs are very good at executing them. Exceptions, on the other hand, are very expensive. The program must stop, then incrementally unravel the the call stack until it reaches some level where it can be caught. Let's say this is your call stack:

Code: Select all

Vector::divide(float)
Player::interact()
Terrain::handleCollision()
Collidable::resolve(Collidable)  <- this catches exceptions of type CollisionException
CollisionManager::resolveCollisions()
World::step()
Game::run() <- this catches all exceptions
main()
This is actually a fairly small call stack compared to many applications, but it's large enough to demonstrate my point. If Vector::divide throws an exception when you divide by zero, it will stop. Then it will check if Player::interact() can handle it. If it can't, it moves up to Terrain::handleCollision(), then so on until it gets to Game::run(), where it finally stops. Each step is an expensive operation requiring manipulation of the call stack.

And even in the simpler case of Vector::divide throwing a CollisionException, the runtime still has to unwind half the stack before it gets handled.

On the other hand, conditionals and returns are both dead-simple and quick to execute. Although it may not be quite as "flexible" to handle errors this way, the added complexity and cost of exceptions make it perfectly reasonable to avoid them.