33

Is left-to-right evaluation of logical operators (&& ||) guaranteed?

Let's say I have this:

SDL_Event event;

if (SDL_PollEvent(&event)) {
    if (event.type == SDL_QUIT) {
            // do stuff
    }
}

Is this guaranteed to be the same as this?

SDL_Event event;

if (SDL_PollEvent(&event) && event.type == SDL_QUIT) {
    // do stuff
}

This can also be very important, let's say we have two requirements, a and b. Requirement a is much more likely to fail then b. Then it's more efficient to say if (a && b) than if (b && a).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
orlp
  • 112,504
  • 36
  • 218
  • 315
  • 4
    A classic, important use for the sequencing implied by `&&` is testing for null pointers before use: `if (a != 0 && a->b != 0 && a->b->c != 0) { somefunc(a->b->c->d); }`. The sequence is critical to avoiding core dumps. (And I'm ignoring the Law of Demeter for the purposes of exposition!) – Jonathan Leffler Apr 15 '11 at 23:01
  • @Jonathan: I ignore it for the purpose of getting any work done! – Steve Jessop Apr 15 '11 at 23:04
  • 1
    These are not "comparison" operators. – Ben Voigt Jul 25 '17 at 22:08

1 Answers1

50

Yes, it's guaranteed, otherwise such operators would lose much of their usefulness.

Important notice: this is valid only for the builtin && and ||; if some criminal overloads them, they are treated as "regular" overloaded binary operators, so in this case both operands are always evaluated, and in unspecified order as usual. For this reason, never overload them - it breaks a hugely important assumption about the control flow of the program.


Relevant standard quotations

Builtin && and || have guaranteed short-circuit behavior

§5.14 ¶1

Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.

§5.15 ¶1

Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.

If overloaded, they behave as "regular" binary operators (no short-circuit or guaranteed ordering of evaluation)

§13.5 ¶9

Operators not mentioned explicitly in subclauses 13.5.3 through 13.5.7 act as ordinary unary and binary operators obeying the rules of 13.5.1 or 13.5.2.

and && and || are not mentioned explicitly in these subclauses, so regular §13.5.2 holds:

§13.5.2 ¶1

A binary operator shall be implemented either by a non-static member function (9.3) with one parameter or by a non-member function with two parameters. Thus, for any binary operator @, x@y can be interpreted as either x.operator@(y) or operator@(x,y).

with no special provision for evaluating only one side or in a particular order.

(all quotations from the C++11 standard)

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 1
    By the way, keep in mind that, if you have "simple" conditions (e.g. your second one) branching can cost more than evaluating the condition itself. – Matteo Italia Apr 15 '11 at 22:50
  • Matteo Italia: `a` and `b` were hypothetical. They might've been `IsPrime(n)` and `IsEven(n)`, in which the right order is pretty obvious and serious savings can be made. – orlp Apr 15 '11 at 22:53
  • @nightcracker: sure, I was just pointing out a small but common misconception. :) – Matteo Italia Apr 15 '11 at 22:58
  • 1
    Conditions without side-effects can be moved anywhere the compiler likes. The compiler is allowed to eliminate a branch. – Potatoswatter Apr 15 '11 at 23:06
  • 1
    @MatteoItalia: it's _very_ important to note that if you override `operator&&` or `operator||` then it's treated like a regular function call, and the left-to-right evaluation is no longer guaranteed.[ – Mooing Duck Jul 25 '17 at 22:17
  • @MooingDuck: yep, that's really important indeed; added the remark and the relevant standard quotations. – Matteo Italia Jul 26 '17 at 09:20