How Does C++ Handle &&? (Short-Circuit Evaluation)

How does C++ handle &&? (Short-circuit evaluation)

Yes, the && operator in C++ uses short-circuit evaluation so that if bool1 evaluates to false it doesn't bother evaluating bool2.

"Short-circuit evaluation" is the fancy term that you want to Google and look for in indexes.

The same happens with the || operator, if bool1 evaluates to true then the whole expression will evaluate to true, without evaluating bool2.

In case you want to evaluate all expressions anyway you can use the & and | operators.

Is short-circuiting logical operators mandated? And evaluation order?

Yes, short-circuiting and evaluation order are required for operators || and && in both C and C++ standards.

C++ standard says (there should be an equivalent clause in the C standard):

1.9.18

In the evaluation of the following expressions

a && b
a || b
a ? b : c
a , b

using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).

In C++ there is an extra trap: short-circuiting does NOT apply to types that overload operators || and &&.

Footnote 12: The operators indicated in this paragraph are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation, and the operands form an argument list, without an implied sequence point between them.

It is usually not recommended to overload these operators in C++ unless you have a very specific requirement. You can do it, but it may break expected behaviour in other people's code, especially if these operators are used indirectly via instantiating templates with the type overloading these operators.

C++ short-circuiting of booleans

No, the B==2 part is not evaluated. This is called short-circuit evaluation.

Edit: As Robert C. Cartaino rightly points out, if the logical operator is overloaded, short-circuit evaluation does not take place (that having been said, why someone would overload a logical operator is beyond me).

Does short circuiting make execution of the program faster, and is analysing which statement to put first in the condition statement worth it?

First, make sure you are not a victim of premature optimization.

With that said, make sure that you did everything you could to speedup the bottleneck of your program.


Doing what you said about the short circuiting may be a good idea in certain cases, but that's heavily depends all your statements.

For example, if you have something like:

if(slowFunction() && complexConditionRootsAndExponents && ConditionUsuallyZero)

then you would probably want that last term to be first, wouldn't you?

However, be careful, things are not always trivial to permute in a logical sequence. Check for example my answer in Why this program printed fork 4 times?, where one can see that short circuit can affect the flow of the execution of the program.


TL;DR

In general though, it is rare to get significant speedup by permuting the terms in the conditions. Focus on the bottleneck of your program and tackle that as hard as you can!

Does Objective-C use short-circuit evaluation?

Objective-C does support short-circuit evaluation, just like C.

It seems that in your example myString is NSNull and not nil, therefore myString != nil is true.

NSNull is a singleton and is used to represent nil where only objects are allowed, for example in an NSArray.

Btw, normally, people write if (!myString && myString.length == 0). Comparing to nil is quite ugly. Also, I'd compare the length to 0. That seems to be more clear.

Why is this version of logical AND in C not showing short-circuit behavior?

This is a trick question. b is an input argument to the sc_and method, and so will always be evaluated. In other-words sc_and(a(), b()) will call a() and call b() (order not guaranteed), then call sc_and with the results of a(), b() which passes to a?b:0. It has nothing to do with the ternary operator itself, which would absolutely short-circuit.

UPDATE

With regards to why I called this a 'trick question': It's because of the lack of well-defined context for where to consider 'short circuiting' (at least as reproduced by the OP). Many persons, when given just a function definition, assume that the context of the question is asking about the body of the function; they often do not consider the function as an expression in and of itself. This is the 'trick' of the question; To remind you that in programming in general, but especially in languages like C-likes that often have many exceptions to rules, you can't do that. Example, if the question was asked as such:

Consider the following code. Will sc_and exibit short-circuit behavior when called from main:

int sc_and(int a, int b){
return a?b:0;
}

int a(){
cout<<"called a!"<<endl;
return 0;
}

int b(){
cout<<"called b!"<<endl;
return 1;
}

int main(char* argc, char** argv){
int x = sc_and(a(), b());
return 0;
}

It would be immediately clear that you're supposed to be thinking of sc_and as an operator in and of itself in your own domain-specific language, and evaluating if the call to sc_and exhibits short-circuit behavior like a regular && would. I would not consider that to be a trick question at all, because it's clear you're not supposed to focus on the ternary operator, and are instead supposed to focus on C/C++'s function-call mechanics (and, I would guess, lead nicely into a follow-up question to write an sc_and that does short-circuit, which would involve using a #define rather than a function).

Whether or not you call what the ternary operator itself does short-circuiting (or something else, like 'conditional evaluation') depends on your definition of short-circuiting, and you can read the various comments for thoughts on that. By mine it does, but it's not terribly relevant to the actual question or why I called it a 'trick'.

short circuiting and parenthesis

It is relatively easy to prove the equivalence for two simplified cases of three subexpressions:

a && (b && c)  -->  a && bc   // bc is a shorthand for b && c

Here, a will be evaluated first. If it is false, short circuiting will prevent the evaluation of bc. If it is true, bc will be evaluated, that is, b && c will be evaluated. If b is false, c won't be evaluated.

(a && b) && c  -->  ab && c   // ab is a shorthand for a && b

Here, ab will be evaluated first. (That is a && b is evaluated first. If a is false, short circuiting will prevent the evaluation of b. Otherwise, ab yields b.) If ab is false, c won't be evaluated.


Now, if you prefer evidence to proof, you can look at the assembly output of the following C code:

int a(), b(), c(), d();

void e()
{
a() && b() && c() && d();
}

void f()
{
a() && (b() && (c() && d()));
}

void g()
{
(a() && b()) && (c() && d());
}

void h()
{
((a() && b()) && c()) && d();
}

(I used C code as opposed to C++ code to prevent name mangling.)

generated assembly for e:

_e:
// ... enter ...
call _a
testl %eax, %eax
je L1
call _b
testl %eax, %eax
je L1
call _c
testl %eax, %eax
je L1
call _d
testl %eax, %eax
nop
L1:
// ... leave ...

generated assembly for f:

_f:
// ... enter ...
call _a
testl %eax, %eax
je L4
call _b
testl %eax, %eax
je L4
call _c
testl %eax, %eax
je L4
call _d
testl %eax, %eax
nop
L4:
// ... leave ...

generated assembly for g:

_g:
// ... enter ...
call _a
testl %eax, %eax
je L7
call _b
testl %eax, %eax
je L7
call _c
testl %eax, %eax
je L7
call _d
testl %eax, %eax
nop
L7:
// ... leave ...

generated assembly for h:

_h:
// ... enter ...
call _a
testl %eax, %eax
je L10
call _b
testl %eax, %eax
je L10
call _c
testl %eax, %eax
je L10
call _d
testl %eax, %eax
nop
L10:
// ... leave ...

As you can see, apart from labels, the generated assembly code is completely identical.

if statement - short circuit evaluation vs readability

One natural solution would look like this:

bool b1 = SomeCondition();
bool b2 = b1 || SomeOtherCondition();
bool b3 = b2 || SomeThirdCondition();
// any other condition
bool bn = bn_1 || SomeFinalCondition();

if (bn)
{
// do stuff
}

This has the benefits of being easy to understand, being applicable to all cases and having short circuit behaviour.


This was my initial solution: A good pattern in method calls and for-loop bodies is the following:

if (!SomeComplicatedFunctionCall())
return; // or continue

if (!SomeOtherComplicatedFunctionCall())
return; // or continue

// do stuff

One gets the same nice performance benefits of shortcircuit evaluation, but the code looks more readable.

Short circuit error handling in C

I've seen the use of GOTOs in C for this exact purpose.

Because there isn't a 'finally' construct in C, a method was needed to free all your memory even if you were exiting a function early.

So it's essentially as follows
(could someone correct my C syntax if I'm wrong, I'm a bit rusty)

int foo()
{
/* Do Stuff */
if(!DoSomething())
GOTO Failure;

if(!DoSomething2())
GOTO Failure;

if(!DoSomething3())
GOTO Failure;

/* return success */
return true;

Failure:
/* release allocated resources */
/* print to log if necessary */
return false;
}

Important note
Do not use GOTOs for execution flow. They should only be used on error, and only to go to the end of the current function. If you use them for anything else, you're creating spaghetti code that could possibly destroy the fabric of reality. Just don't do it.

EDIT

As one of the posters noted, using Exit(x) will kill your entire program, which keeps that solution reserved for fatal errors. However your original proposed solution (DS() && DS2() && DS3()) all on one line poses a problem for error handling.

If you wanted to wrap the functions in some sort of function specific error handling, there is no way to do it when you wrap the function calls all in one line. So, at the very least you could do something like

int result1 = 0;
int result2 = 0;
int result3 = 0;

result1 = DoSomething();

if(result1)
result2 = DoSomething2();

if(result2)
result3 = DoSomething3();

return result1 && result2 && result3;

Because this method would not preclude error handling.

Why doesn't it short-circuit when you multiply the return value of a function by zero?

Short-circuit evaluation is mandatory for && (logical and), || (logical or) and ? (ternary operator). For the remaining operators it is an (optional) optimization.

The evaluation of fact(5) in the expression 0 * fact(5) can't be in general optimized away just because you know that the outcome of the whole expression is 0 since a call to fact() may introduce side effects (e.g., modify some global variable), so it must be called.

As said in this comment, a good compiler will optimize away the call to fact(5) if it can prove that there are no side effects.



Related Topics



Leave a reply



Submit