Suppose you wanted to declare a variable, as already noted:
void foo() {
Then the semantic constructor is executed after {before} and before {after}.
If this is done at run time, it is covered by the as-if rule. That is, in order to provide optimization, the Standard offers only guarantees about observable effects: regardless of the chosen execution model, the observable effects should be as if the code was executed without any optimization.
Observed effects, in particular, include:
- changing
volatile variables - system calls (including memory operations)
By default, a function whose definition is unknown should have observable effects.
A notable exception is the Elision copy optimization, which the Standard allows in some cases, even if the copy constructor may have observable effects.
Specifically, this means that this:
int before(); int after(); void foo() { int n = 5; int const a = before(); n += a; MyClass m; int const c = after(); n += c; std::cout << n << "\n"; }
The standard guarantees the following order:
before();MyClass m;after();std::cout << n << "\n";
However, it is not guaranteed how n calculated. All that is known is that at the time of printing it will be equal to 5 + a + c , but regardless of whether the calculation is delayed just before printing or is performed impatiently every time a new item is available, it does not concern you : it does not change the observed behavior.
Therefore, the following two versions of foo equivalent:
void foo_eager() { int n = 5; n += before(); MyClass m; n += after(); std::cout << n << "\n"; } void foo_lazy() { int const a = before(); MyClass m; int const c = after(); std::cout << (5 + a + c) << "\n"; }