Side Effects and Sequence Points

January 8-10 January 13-17 January 20-24 January 27-31 February 3-7 February 10-14 February 24-28 March 3-7 March 10-14 March 17-21 March 31-April 4 April 7-11
Definition:

Side Effect: With respect to function usage, a side effect is any effect of one function upon another function that is not part of the explicitly defined (and documented) relationship between the functions.

A more general definition is that a side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated.

Possible causes:

Local versus global variables:
- accessing a global variable. The intent might have been to declare a local variable with name precedence over a global variable and the declaration of the local variable is accidentally omitted. Consequently, you think that your code is modifying a local variable but it is the global variable that is actually modified. This type of side effect is possible any time that global variables are in use and it could occur in any function. Debugging this kind of error is not easy.
Call by Reference:
- Reference parameters by their very nature of allowing two-way passing of information between the calling function and the called function are a potential source of side effects from careless coding in a function. Any changes to reference paramters need to be intentional and carefully documented. Using "const" to specify that a reference parameter may not be altered in the function helps to avoid unintended side effects.
Debugging:
- the symptoms of side-effect errors are typically misleading in that the errors become evident in a part of the program that is not connected to where the error actually originated.
Recommendations:
- avoid global variables. Functions should use only local variables and parameters.
- incoming parameters should be call by value parameters or declared as "const"
- manipulation of outgoing or two-way parameters must be well documented and the code carefully examined for potential mistakes.

Sequence Points

Definition

A sequence point guarantees that all side effects of previous evaluations will be complete. The terminology has changed in C++11, the latest standard for the language. Now it is said that one evaluation is sequenced before another. See Order of Evaluation. If two evaluations can overlap, they are said to be unsequenced. The phrase "undefined behaviour rule" is also used to indicate that results are dependent on the code sequence generated by the compiler.

C++ programmers need to be aware of sequence points and side effects resulting from the order of evaluation of expressions.

For example: given x = 1; f(++x, ++x);, you may expect a call to f(2, 3) but it's actually undefined behaviour. This behaviour is left undefined so the compiler's optimiser has the freedom to arrange evaluations with side effects to run in the most efficient order possible. Parallel processing is another aspect of this. As well, detecting such conditions would significantly increase the complexity of writing a C++ compiler.

Side effects when passing objects to function in C++

When calling a function, all the parameters must have been completely evaluated - and their side effects triggered - before the function call takes place. BUT, there are no restrictions on the compiler related to evaluating specific parameter expressions before any other. They can be overlapping, in parallel etc.. So, in f(expr1, expr2) - some of the steps in evaluating expr2 might run before anything from expr1, but expr1 might still complete first - it's undefined.

The same principles apply to functions, with the return value in place of the result of the expression.

int fcn(int a, int b) 
{ 
return a + b; 
}

This function just computes a return value. Nothing else is altered. Therefore it has no side-effects.

int fcn(int &a, int &b) 
{ 
return ++a + b; 
} 

This function does have a side-effect. The call by reference for parameters a and b cause a modification of the corresponding arguments in the calling function. That is, modifying the calling function's arguments is an additional effect of the function beyond simply computing a return value.

A few examples:

i = v[i++];       // the behavior is undefined 
i = 7, i++, i++;  // i becomes 9. The comma is a sequence point. 
i = ++i + 1;      // the behavior is undefined 
i = i + 1;        // the value of i is incremented
Resources:

Sample files

  • side_effects.cpp The side effect here is caused by forgetting to declare a local variable in the function. This results in a global variable being used for a different purpose than its original intent.
  • side_effects2.cpp Side effect caused by a unary operator.
Textbook coverage

Side effects are not covered as a specific topic in the textbook. There is a Wikipedia definition.