I was wondering if it's possible for C++ compilers to optimize in a case like this. Assume we have a class like:
class Foo {
public:
Foo() : a(10), b(11), c(12) {};
int a;
int b;
int c;
};
And I use this class like:
int main(int argc, char *argv[]) {
Foo f;
f.a = 50;
f.b = 51;
f.c = 52;
return 0;
}
Would the compiler generate code to set a, b, and c to their respective default values of 10, 11, 12, and then set them to 50, 51, 52? Or is it allowed to delay assigning those initial values and instead only ever assign the values later (50,51,52) since there is no read in between the writes? Basically will it have to generate code to write those six values, or can it optimize to three?
If so, does this apply also to more complex types (structs, classes)? What is it called and where can I read more about this?
If not, why not?
This obviously depends on the compiler--but there are certainly at least some compilers that can and will eliminate the dead stores. In fact, depending on how you use the results, the compiler may eliminate all stores, dead or otherwise.
For example, if we compile your code exactly as it is right now, we end up with assembly language like this:
xor eax, eax
ret
That's it--since you never use any of the values you store, it eliminates all the code dealing with those values entirely. All that's left is the fact that main returns 0, so it just generates code for main to return zero.
That's probably not a case you care a whole lot about though, so let's expand the code a bit, to show something closer to what you probably care about.
#include <iostream>
class Foo {
public:
Foo() : a(10), b(11), c(12) {};
int a;
int b;
int c;
friend std::ostream &operator<<(std::ostream &os, Foo const &f) {
return os << "(" << f.a << ", " << f.b << ", " << f.c << ")";
}
};
int main() {
Foo f;
f.a = 50;
f.b = 51;
f.c = 52;
std::cout << f << "\n";
}
In this case, the compiler still eliminates all the storage involved, and produces code to just directly write out the values we gave as literals in the source:
mov esi, 50
mov edi, OFFSET FLAT:std::cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
[and the same sequence repeated for 51 and 52].
Reference:
Godbolt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With