I'm packing bools together in a c++ struct and I want to initialize them all to zero when constructed.
Is this a correct/safe way to do it?
I think it is but I'm not 100% sure and I'd like the lawyers to weigh in...
struct packed_flags {
// All the flags (there's less than 16 of them)
bool f1: 1;
bool f2: 1;
bool f3: 1;
bool f4: 1;
// ...
// Pad the struct to a 16-bit size
uint16_t: 0;
// Constructor to initialize them all to 'false'
packed_flags() {
*(uint16_t*)(this) = 0;
}
} flags;
*(uint16_t*)(this) = 0;
is an aliasing violation and therefore undefined behavior. *this
is not of type uint16_t
nor does any object of type uint16_t
exist that is pointer-interconvertible with *this
.
The correct way to force the default constructor to zero all members is to not write any default constructor at all, instead relying on the implicitly-defined one, and explicitly specifying default member initializers instead (since C++20):
struct packed_flags {
// All the flags (there's less than 16 of them)
bool f1: 1 = 0;
bool f2: 1 = 0;
bool f3: 1 = 0;
bool f4: 1 = 0;
// ...
// Pad the struct to a 16-bit size
uint16_t: 0 = 0;
} flags;
Before C++20 you can simply write a default constructor that assigns 0
to each bit-field manually.
Or, even without these default initializers you can use initialization by ()
or {}
, to force zero-initialization (since C++03/C++11):
struct packed_flags {
// All the flags (there's less than 16 of them)
bool f1: 1;
bool f2: 1;
bool f3: 1;
bool f4: 1;
// ...
// Pad the struct to a 16-bit size
uint16_t: 0;
} flags = {};
Also, uint16_t: 0;
is not guaranteed to pad the structure as you want it. It only specifies that the next bit-field shall begin at a new bit-field allocation unit boundary, but there is no following bit-field.
If you want to force the structure to have a specific alignment (implying that its size is an integer multiple of that alignment), then you should use alignas
instead:
struct alignas(2) packed_flags {
// All the flags (there's less than 16 of them)
bool f1: 1;
bool f2: 1;
bool f3: 1;
bool f4: 1;
// ...
} flags = {};