Zeroing Memory is Hard: VC++ 2015 arrays
randomascii.wordpress.com
randomascii.wordpress.com
I hope the Python script is helpful for finding some of the odd variants that currently exist.
> I recently noticed that it’s still an issue in VC++ 2015 Update 3
Seems obvious and elementary enough, but it got me good the other day.
T() = default; template<typename T> struct Function {
Function() = default;
void* callback = nullptr;
};
struct CPU {
Function<void ()> functions[65536]; //= {0} makes no difference
};
int main() {
CPU cpu;
return 0;
}
There's a bug in GCC, at least versions 5.1 - 5.4, where the above code will take 30s-90s to compile (depends on your CPU speed), and eat 500MB+ of RAM in doing it. But the bug isn't in 4.9, and possibly newer GCC releases.What causes it? "Function() = default;" of course. Change it to "Function() {}" and the code compiles in 100ms.
So because I can't tell people, "don't use GCC 5.x", or "don't ever use any of my class objects in a large array", I basically can't use "= default;" syntax on my constructors in any of my library code now :(
Exactly, that's what hosed me. Some double-precision floats ended up with garbage values and I couldn't see how it was happening.
But I believe that rule doesn't apply for any objects where adding an '= default' constructor would be useful, because it requires that there be no user-defined constructors or private/protected members. Otherwise that syntax ultimately calls the default constructor, which won't do any zeroing.
See http://en.cppreference.com/w/cpp/language/aggregate_initiali...
(It's not the fastest way for small sizes --- it actually is for larger sizes, just like REP MOVS --- but the user asked for smaller, not faster code.)
It turns out that our compiler has a minimum size limit in a memset optimization. I’m sure the size limit was there for a Very Good Reason (TM) at one point in time, but we are investigating whether we can remove it. Step one is understanding why it was there in the first place.
That's where auto often helps. Lets you change types as long as you don't break the interface.
I hit this in a game server where a few percent of CPU time (that was enough to count as low-hanging-fruit) was being spent on memset inside of resize().
I have not solved it yet. The best solution - don't use std::vector for anything critical.
You can use it with std::unique_ptr<> to simplify memory management.