C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relax condition for potentially invoked destructor in constructor

From: connor horman <chorman64_at_[hidden]>
Date: Fri, 25 Feb 2022 15:21:16 -0500
On Fri, 25 Feb 2022 at 14:45, organicoman via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Ok, it looks like the thread is still on.
> Call me wrong or everyday Bob or whatever. But here we go.
>
> For me C++ should be intuitive to understand.
> Armed with some logic and sense is enough to understand its construct. No
> need to run to the standard everytime to understand simple things unless
> there is a risk of legacy heritage from C.
>
> In our case, Compilers implementers allowed rearranging the members
> initialization for a reason, i hope it is logic, right?
> So if i have:
> struct base {};
> struct derived: public base{};
> struct mostDerived: public derived
> {
> int a;
> double d;
> mostDerived(): d(3.14), a(123) {}
> };
>
> To get "mostDerived" constructed then i need "derived" constructed.
> In turn, to get "derived" constructed i need "base" constructed.
> So obviously there is an ordering here.
> It does make sense to abide to it.
>
> My question now is:
> -why should i impose this ordering on the data members "a" and "d" in the
> "mostDerived" class?
> -Isn't the same if I constructed "d" then "a" or the other way around?
>
> 1) The initialization order is defined such that it is consistent between
constructors so that the destructor can always ensure that it destroys
objects in reverse order of construction, regardless of the definition of
those constructors
2) The initializer of d may refer to a, including in ways that are invalid
for indeterminate values
3) The destructor of d may refer to a, including in ways that are invalid
for on object for which the lifetime has ended (tied back to destruction
order, which, as stated multiple times in this thread, is always inverse of
initialization order)

In that program, the compiler may 100% reorder or interleave the
initializers under the as-if rule, because neither contains any observable
behaviour, neither contain side effects to the same scalar object, and
neither depends on the other. However, if you can observe the order, that
order is defined in the standard so you can rely on that order.

> Don't tell me the standard says. I want one logic reason or an example.
>
> Also, if my compiler allows me to shuffle the initialization order of data
> members.
> For me, that is a strong guarantee that it will catch the following case
> and process it without error:
> Given the struct: base and derived above,
> struct mostDerived: public derived
> {
> int a;
> double d;
> mostDerived (): d(3.14), derived(), a(123){}
> };
>
> So logically, the compiler should help me here and make sure that this
> constructor produce correct code, right?
> Otherwise i need always to compile my constructor myself before my
> compiler does it. Which is not programming for me.
>
Same deal here. It doesn't actually affect observable behaviour to reorder
these initializers, so the compiler could 100% do what it wants. The issue
is when it becomes observable.
I'm also unsure what you mean by "produce correct code". There's no source
of undefined behaviour that would make this code incorrect, and, as I
observed above, any order would do the exact same thing.

>
> So my proposal, or suggestion, is relaxing this ordering rule on data
> member initialization.
>
> But if this flexibility is not desired, and ppl are content with what they
> have, then it's ok.
>
> I will stop here.
>
> Nadir
>
>
> Sent from my Galaxy
>
>
> -------- Original message --------
> From: Jason McKesson via Std-Proposals <std-proposals_at_[hidden]>
> Date: 2/25/22 10:46 PM (GMT+04:00)
> To: std-proposals_at_[hidden]
> Cc: Jason McKesson <jmckesson_at_[hidden]>
> Subject: Re: [std-proposals] Relax condition for potentially invoked
> destructor in constructor
>
> On Fri, Feb 25, 2022 at 12:30 PM organicoman via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> >
> > Keep in mind that objects are guaranteed to be destroyed in the
> opposite order of construction. If you have multiple constructors that may
> construct your subobjects in different orders, you must also allocate
> run-time memory to record the order of initialization in order for your
> destructor to destroy the objects in the correct order. That's an
> unacceptable cost to a lot of people.
> >
> > What you are talking about here, and i guess most of the participant in
> this discussion, is the base classes of a derived class (known as
> subobjects).
> > For that case. Yes, the order of destruction MUST follow the order of
> construction in reverse, and that is guaranteed by the standard.
> >
> > In our case we are talking about " MEMBER Objects", objects declared
> inside the body of the structure.
>
> Members are a *kind* of subobject.
>
> > The compiler is free to rearrange their layout however it sees fit for a
> compact memory and to avoid extra instruction to fetch a member if it is
> not at the right memory boundary.
>
> The compiler is permitted to insert padding, but it's permitted to do
> that for *any* subobject, base or member. What the compiler is *not*
> allowed to do is rearrange the *order* of members entirely. There are
> cases where the compiler can, but since C++11, that is restricted
> specifically to cases where some members are of different access
> classes, and this reordering can only happen *between* members of
> different access classes. Within an access classes, later members must
> come after earlier ones.
>
> This is explicitly codified in C++20's pointer comparison rules:
>
> > If two pointers point to different non-static data members of the same
> object, or to subobjects of such
> members, recursively, the pointer to the later declared member is
> required to compare greater provided
> the two members have the same access control (11.9), neither member is
> a subobject of zero size, and
> their class is not a union.
>
> So your conclusion arises from faulty premises. The layout of a struct
> must be such where later declared members are later in the object than
> earlier ones, within the same access control. Ordering is not subject
> to the compiler's whims.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2022-02-25 20:21:29