C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Impact of defaulted ctor on value initialization

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Tue, 11 Jul 2023 12:17:43 +0100
On Tue, 11 Jul 2023 at 12:11, Jonathan Wakely <cxx_at_[hidden]> wrote:

>
>
> On Tue, 11 Jul 2023 at 11:17, Ofek Shilon <ofekshilon_at_[hidden]> wrote:
>
>> Thanks for the prompt reply!
>>
>> On Tue, 11 Jul 2023 at 12:53, Jonathan Wakely <cxx_at_[hidden]> wrote:
>>
>>>
>>> Why should Thingy3() = default; give you that behaviour? It's still
>>> trivial and it is noexcept. Why should it prevent Thingy3() from zeroing
>>> the members?
>>>
>> The phrasing of this question assumes zeroing the members is some natural
>> default and deviating from it requires justification. I believe in C++ it's
>> the other way around: you don't pay for what you don't use, so me & quite a
>> few people I talked to would expect `= default` to consistently not
>> initialize the members, in all initialization forms.
>>
>
> But value-initialization zeros things, just like:
> int i = int();
>
> If you don't want that, don't use value-init:
> int i;
> Thingy1 t1;
> Thingy3 t3;
>
> The point is that when you do value-init **you are using** the zero-fill
> feature, so **you pay for it**.
>
> If you don't want to pay for it, don't use it. You have the choice.
>
> I wish people would stop quoting "you don't pay for what you don't use" as
> if it meant you never pay for anything, as though every operation must use
> as few instructions as possible, even if that changes the meaning of the
> code. I'm sorry you and the people you've talked to are surprised about
> what value-initialization does, but that isn't a reason to change how it
> works.
>

The point of the above examples is that `Thingy3() = default;` means
"define it as though I hadn't written it", and so it's the same as your
Thingy1, not the same as your Thongy2.

If you want something that acts exactly like Thingy2, then write exactly
that.

As the example below shows, there would be no way to get the "define it as
though I hadn't written it" behaviour for Thingy4 if it worked how you
want. To add a default ctor where it would otherwise be deleted, you could
only have it be like a non-trivial, user-provided default ctor. Why remove
a useful feature that we have today just to be able to write the same thing
in two different ways? Actually it would be three different ways, because
you can also do this to get the behaviour you want:

struct Thingy6 {
  Thingy6();
};
Thingy6::Thingy6() = default;

Don't take away the current behaviour of Thingy3 when that can't be
achieved any other way, making it do the same as Thingy2 and Thingy6 which
can already be done.






>
>
>> One could just as well ask: "Why should `=default` prevent `Thingy3 t3;`
>> from zeroing the members?" - except that it does, and it is very natural
>> to expect consistent impact of `=default`.
>>
>>>
>>> If defining it as defaulted behaved how you want, then there would be no
>>> way to say "it's default constructible, but I still want it to be trivial".
>>> If you do want it to be non-trivial, you can already do that, as you did
>>> for Thingy2.
>>>
>> Not sure I understand this, and if I do - not sure I agree. If you want
>> to say "it's default constructible, but the ctor zeros members" (is that
>> what you mean by 'trivial'?) then there certainly is a way to express it:
>> just write a default ctor that zeros the members.
>>
>
> No, that would not be a trivial constructor.
>
> https://en.cppreference.com/w/cpp/language/default_constructor#Trivial_default_constructor
>
> Your suggestion would **remove** functionality from the language. It would
> no longer be possible to have a class with a user-declared copy/move/other
> constructor and a trivial default constructor, so you would have to pay for
> functionality (non-trivial default constructor) that you don't want.
>
> As currently defined, C++ allows you to do this:
>
> struct Thingy4 {
> Thingy4() = default;
> Thingy4(int);
> };
> static_assert( std::is_trivially_default_constructible_v<Thingy4> );
>
> The default constructor has to be user-declared because of the
> user-provided Thingy4(int) ctor, otherwise it has a deleted default ctor.
>
> Your preferred behaviour would remove the ability to write the code above,
> because Thingy4() would be non-trivial.
>
> If you want that, you can already do it, we don't need to change
> Thingy4()=default to do that:
>
> struct Thingy5 {
> Thingy5() {}
> Thingy5(int);
> };
> static_assert( ! std::is_trivially_default_constructible_v<Thingy5> );
>

Received on 2023-07-11 11:17:57