Another question discusses the legitimacy for the optimizer to remove calls to new
: Is the compiler allowed to optimize out heap memory allocations?. I have read the question, the answers, and N3664.
From my understanding, the compiler is allowed to remove or merge dynamic allocations under the "as-if" rule, i.e. if the resulting program behaves as if no change was made, with respect to the abstract machine defined in the standard.
I tested compiling the following two-files program with both clang++ and g++, and -O1
optimizations, and I don't understand how it is allowed to to remove the allocations.
// main.cpp
#include <cstdio>
extern int g_alloc;
static int* foo(int n)
{
// operator new is globally overridden in the other file.
return new int(n);
}
int main(int argc, char** argv)
{
foo(argc);
foo(argc*2);
printf("allocated: %d\n", g_alloc);
return g_alloc;
}
// new.cpp
#include <cstdio>
#include <cstdlib>
#include <new>
int g_alloc = 0;
void* operator new(size_t n)
{
g_alloc += n;
printf("new %lu\n", n);
return malloc(n);
}
The idea is to override the default operator new(size_t)
with a function with side effects: printing a message and modifying a global variable, the latter being used as the exit code.
The side effects do not impact the allocation itself but it still change the output of the program. Indeed, when compiled without optimizations, the output is:
new 4
new 4
allocated: 8
But as soon as optimizations are enabled, the output is:
allocated: 0
The result is the same with when using standards 98 to 17.
How is the compiler allowed to omit the allocations here? How does it fit the as-if rule?