C++ Logo

std-proposals

Advanced search

Re: [std-proposals] A type trait to detect if value initialization can be achieved by zero-filling

From: Giuseppe D'Angelo <giuseppe.dangelo_at_[hidden]>
Date: Mon, 30 Jan 2023 12:20:09 +0100
Hello,

Il 30/01/23 07:04, Jason McKesson via Std-Proposals ha scritto:
> On Sun, Jan 29, 2023 at 8:36 PM Giuseppe D'Angelo via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>>
>> Hello,
>>
>> Il 29/01/23 22:11, Jason McKesson via Std-Proposals ha scritto:
>>> On Sun, Jan 29, 2023 at 3:41 PM Giuseppe D'Angelo via Std-Proposals
>>> <std-proposals_at_[hidden]> wrote:
>>>>
>>>> Hello,
>>>>
>>>> As per subject, I've been working on a proposal for a standardized way
>>>> to detect if a trivially default constructible type can be value
>>>> initialized by using `memset(0)` on some suitable storage.
>>>>
>>>> A draft is available here:
>>>>
>>>> https://isocpp.org/files/papers/D2782R0.html

I've updated the draft incorporating many of the raised comments.


>>> However, I would suggest that it should be equally true/false for all
>>> pointers of the same category: object pointers, function pointers, and
>>> member pointers. Either all object pointers are
>>> trivially-zero-initializable or none of them are. Etc.
>>
>> Is there any reason for this? On Itanium, pointers to objects and to
>> functions can be zero-filled. Pointers to data members cannot. Why not
>> having the trait giving the factually correct answer? Surely one would
>> want a vector of `string_view`s to be zero-filled.
>
> I may not have explained what I meant very well.
>
> There are 3 categories of pointers: object pointers, function
> pointers, and member pointers. All pointers of a *particular* category
> have to give the same answer. So all object pointers are either
> trivially zero initializable or not. But all function pointers could
> have a *different* answer. Etc. So on Itanium, they could have
> function and object pointers be trivially zero initializable, but not
> member pointers.
>
> What it can't do is have `int*` be trivially zero initializable but
> `float*` not be.

Ok, I got it now. But again, why imposing anything? We're entirely in
implementation-defined territory. "Who cares" if on some fancy
architecture `int *x=0;` is zero-filled and `float *y=0;` is not? The
compiler will tell you the truth for each different type.


>> I'm really really really not sure about the implications of adding
>> implicit lifetime types to the mix. What you say above makes lots of
>> sense, but how in the world is the compiler supposed to know if
>>
>> struct Foo {
>> int i;
>> Foo(); // non-trivial, user-provided, out of line, ...
>> };
>>
>> can or cannot be value-initialized by zero-filling storage? Foo is an
>> implicit-lifetime class: it has a trivial _copy_ constructor and trivial
>> destructor.
>
> That's a fair point. A type cannot undergo trivial zero initialization
> if it cannot undergo zero initialization at all. Even if force-feeding
> it zeros is a valid value representation, getting to that state is not
> "zero initialization".

Right, but it would still make lots of sense to be able to zero-fill
storage for an implicit-lifetime type such as

class string_view {
    const char *b, *e;
public:
    // not trivial
    string_view() : b(nullptr), e(nullptr) {}
};

and then use start_lifetime_as or so.

Since the compiler cannot possibly help here, the only way I see to add
support for this kind of types is to make the trait a customization
point and/or add an attribute to opt-in into the detection (à la
[[trivially_relocatable]]). This is an interesting idea, but I'm leaving
it as a future extension. I've added a discussion in the paper.



Thank you again for the feedback,

-- 
Giuseppe D'Angelo

Received on 2023-01-30 11:20:12