C++ Logo

std-discussion

Advanced search

Re: Is [[indeterminate]] not applicable to data members?

From: Andrew Schepler <aschepler_at_[hidden]>
Date: Sun, 16 Mar 2025 14:01:30 -0400
There's another difference that occurs to me between [[indeterminate]] on a
member vs. on a complete object. Say we have a class with a number of
members, and one of them is "std::byte buffer[N];". The class will have
"proper constructors", meaning every byte of "buffer" will be initialized
or assigned before the constructor returns, and we'll document that it
might be efficient to mark automatic-storage objects of the class
[[indeterminate]].

(Often talking about a class with a number of different members brings up
the Single Responsibility Principle or RAII, and a suggestion to move the
thing with special behavior into its own type. That doesn't help in this
case. The members could be well-encapsulated, actually in different classes
and objects, but the complete object still has the same issue.)

But what about the rest of the bytes in the complete object? If it's
important to make sure none of them have indeterminate values, these
"proper constructors" should do something with all the padding bits, but
have to do it after some subobjects already initialized. Even if we
forget about portability, trying to determine and zero all padding bits,
preserving the subobjects that were already initialized, not touching any
vptrs, etc. can become an ugly mess. (And if there are value representation
bits and padding bits in the same byte, I think "bytref &= mask;" would
technically be UB anyway, leaving no way to actually do it.)

Allowing [[indeterminate]] on the class member would leave that job to the
implementation, ensuring the only storage that's initially indeterminate is
that one buffer.

We could have an analogous issue if we expect a class or variable will/may
be used for bytewise output of some sort and want to prevent all EB.
There's no simple and convenient way to explicitly prewrite a variable's
memory before some non-trivial initialization is done by the variable's
definition.

For both cases, one workaround might be to put an (anonymous?) union or
only raw storage in the class, have the constructor first zero-fill all the
memory (except a block starting at offsetof a specific member if
applicable), and then placement-new all the actual data.

Maybe some other sort of way to specify the interactions of complete object
attribute and class behavior would be useful?

-- Andrew Schepler

Received on 2025-03-16 18:01:44