Order of parameter evaluation in C++

The low-level details of how data gets passed into a function are often overlooked by programmers. We obviously care about passing by value vs. reference, and perhaps also by copy vs. move, but it’s easy to ignore anything deeper than that.

With C++ in particular, this can cause an unexpected problem regarding the order in which things actually happen. In this post, we’ll look at what can go wrong, and how to deal with it.

Simple example

Let’s say we’ve got a function which needs to be given two numbers. However, we don’t have those numbers stored in variables yet. Rather, we need to call two other functions to get those values. For example:

#include <iostream>
 
void doStuff(int a, int b) { }
 
int getA() { std::cout << "A"; return 1; }
int getB() { std::cout << "B"; return 2; }
 
void main()
{
    doStuff( getA(), getB() );
}

What is the execution path in main()?

Obviously getA() and getB() must both be called before doStuff() can be called. That much absolutely must be true.

However, it’s tempting to make the false assumption that getA() will be called before getB().

In reality, this may not be the case. If you run the program, the output is likely to be “BA”, indicating that the parameters were evaluated in reverse order. Note that it depends on your compiler though. In theory, you may see different results depending on which one you use.

Why does this happen?

The C++ standard does not specify the order in which function parameters need to be evaluated. The calling convention dictates the order in which the parameters are passed, but there’s no requirement to evaluate them the same way.

In my experience though, it’s common to see the parameters evaluated in reverse order (right-to-left). Hypothetically, a compiler may change the order if there is (for example) some opportunity for performance gain, but it seems unlikely.

Conclusion

The example above simply uses console output to illustrate the problem. However, if you are careless with your coding it’s easy to end up with something more serious. The underlying issue can often be hidden because the evaluations have side effects which you didn’t consider, such as relying on the result of calculations, or even on instantiation of objects.

The rule here is simple: do not write code which relies on a particular order of parameter evaluation. If you need parameters to be evaluated in a particular order then do so before the function call.

Leave a Reply

Your email address will not be published. Required fields are marked *