C++ Logo

std-discussion

Advanced search

Re: [basic.life]/8.5 interpretation

From: jim x <xmh970252187_at_[hidden]>
Date: Fri, 11 Sep 2020 13:38:48 +0800
This also means, `x.i == 5` is invalid even if in c++17. Because such a
`newly created subobject` does not satisfy that it will be created in the
storage *after the lifetime of an object has ended and before the storage
which the object occupied is reused or released.*
Maybe this condition is a defect. Or, the intent of the standard indeed
means this. So, for your example `x.i == 5;`, whether `x.i` is required to
launder or not, is determined by the condition, irrelevant of these
conditions listed in the below.

However, Please note the last sentence in the document [basic.life], it
is:
>
In this subclause, “before” and “after” refer to the “happens before”
relation ([intro.multithread] <https://eel.is/c++draft/intro.multithread>).
<https://eel.is/c++draft/basic.life#11.sentence-1>

[Note <https://eel.is/c++draft/basic.life#11.note-1>:
*Therefore, undefined behavior results if an object that is being
constructed in one thread is referenced from another thread without
adequate synchronization.
<https://eel.is/c++draft/basic.life#11.sentence-2> *— *end note*].

So, these rules intend to cover the multithread situations. So, my reading
is, `after the lifetime of an object has ended` means that call destructor
explicitly or reuse the storage occupied by the object, which would end the
lifetime of such an object. And `before the storage which the object
occupied is reused or released.` means that in other threads, there's no
such operation that will occupy the storage or release the storage. That
will make sense.

jim x <xmh970252187_at_[hidden]> 于2020年9月11日周五 下午12:00写道:

> From the condition, I agree with this opinion. And the example that
> follows the rule [basic.life#8] evidences this opinion. that is, call
> destructor `this->~C();` explicitly. However, I argue here, is that, this
> condition will contradict with [intro.object#2]
> <https://eel.is/c++draft/intro.object#2>, that means, the new created
> subobject would never be accessed by the original name which refers to the
> subobject.
>
> John Mousseau <jhnmou20_at_[hidden]> 于2020年9月11日周五 上午6:33写道:
>
>> In your example, the whole struct is replaced, so that the condition is
>> easily fulfilled by the old and new S object both being complete objects,
>> and the part with p1 and p2 isn't required, I think.
>> In my example, however, only a subobject is replaced. After some
>> consideration, I think jim x is probably right that they can be the same.
>> It would be weird if such a simple replacement wasn't intended to be
>> defined anymore, when it worked in c++17. However, I think some
>> consideration should be given to the beginning of [basic.life]/8 in
>> general. Strictly speaking, it describes the situation in which such a
>> replacement is possible as:
>> "If, *after the lifetime of an object has ended and before the
>> storagewhich the object occupied is reused* or released, a new object is
>> created at the storage location which the original object occupied."
>>
>> But technically, the lifetime of the old object was only ended *because*
>> its storage was reused. It could be interpreted in such a way that it is
>> required to explicitly end the lifetime of the old object (by calling a
>> destructor) *before* the placement-new expression. I saw an SO post in
>> which a pretty reputable user interpreted it in this way and inferred the
>> following?
>>
>> struct X {int i; float j;} x;
>> int& ir = x.i;
>> x.~X();
>> new (&x) X{};
>> bool b = ir == 5; // well-defined
>> new (&x) X{};
>> b = ir == 5; // undefiend because lifetime of X wasn't ended so
>> basic.life/8 doesn't apply.
>>
>> Is this a sensible interpretation? If that was true than it might not be
>> possible to replace non-class objects at all. (Unless the psedo-destructor
>> ends their lifetime? :/ )
>>
>>
>>
>> Am Do., 10. Sept. 2020 um 12:30 Uhr schrieb <language.lawyer_at_[hidden]>:
>> I think, p1 p2 must be the old and the new objects, they can't be the
>> same object.
>> I assume p1 and p2 are needed for the following code:
>>
>> struct S { int i; };
>>
>> S s {};
>> int& ri = s.i;
>>
>> new (&s) S {};
>>
>>
>> where the wording guarantees that `ri` will refer to the new int
>> subobject (o2) of the object of type S (p2)
>>
>>
>> On 10/09/2020 12:43, jim x via Std-Discussion wrote:
>> > I think your first opinion is the intent of the rule. Because,
>> according
>> > to the rule [intro.object#2] <https://eel.is/c++draft/intro.object#2>,
>> the
>> > new object has became the subobject of the object X, and the condition
>> "o1
>> > and o2 are direct subobjects of objects P1 and P2" is true. The standard
>> > does not say `P1` and `P2` shall not be the same object, the object
>> > `X` itself satisfies all rules listed in [basic.life#8]
>> > <https://eel.is/c++draft/basic.life#8>. So, there's no necessary to use
>> > `std::launder`.
>> >
>> > John Mousseau via Std-Discussion <std-discussion_at_[hidden]>
>> > 于2020年9月9日周三 上午1:49写道:
>> >
>> >> Dear list members,
>> >>
>> >> in draft N4860 <https://isocpp.org/files/papers/N4860.pdf>, which I
>> >> assume is close to C++20, the wording of [basic.life]/8 differs from
>> C++17
>> >> in that the notion of "transparently replaceable" was involved. I am
>> >> wondering whether condition 8.5 of that paragraph allows for p1 and p2
>> to
>> >> be the same object.
>> >>
>> >> Consider the following most trivial example:
>> >>
>> >> struct X {int i; float f;};
>> >> X x{3, 3.f};
>> >> new(&x.i) int(5);
>> >> // x.i == 5 without launder? True in C++17.
>> >>
>> >> According to C++17's wording this is surely the case as there is no
>> >> const-qualification involved at all. However, in the newest wording,
>> while
>> >> conditions (8.1) through (8.4) are fulfilled (for o1 and o2 being the
>> old
>> >> and new int respectively), condition (8.5) might be unfulfilled, as
>> neither
>> >> are both objects complete, nor are they subobjects of (different)
>> objects
>> >> p1 and p2, unless, by [intro.object]/2, the new int becomes a
>> subobject of
>> >> x, and when then consider p1 and p2 of [basic.life]/8.5 to be
>> identical. If
>> >> we then consider x to be transparently-replaceable by itself, the
>> condition
>> >> would be fulfilled. Is that the intended interpretation or is the
>> intention
>> >> that the access in my example now requires std::launder even though no
>> >> constness is involved?
>> >>
>> >> Sorry in case I am not seeing the obvious and thank you for your time.
>> >>
>> >> Best Regards
>> >> John Mousseau
>> >> --
>> >> Std-Discussion mailing list
>> >> Std-Discussion_at_[hidden]
>> >> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>> >>
>> >
>> >
>>
>> Am Do., 10. Sept. 2020 um 12:30 Uhr schrieb <language.lawyer_at_[hidden]>:
>>
>>> I think, p1 p2 must be the old and the new objects, they can't be the
>>> same object.
>>> I assume p1 and p2 are needed for the following code:
>>>
>>> struct S { int i; };
>>>
>>> S s {};
>>> int& ri = s.i;
>>>
>>> new (&s) S {};
>>>
>>>
>>> where the wording guarantees that `ri` will refer to the new int
>>> subobject (o2) of the object of type S (p2)
>>>
>>>
>>> On 10/09/2020 12:43, jim x via Std-Discussion wrote:
>>> > I think your first opinion is the intent of the rule. Because,
>>> according
>>> > to the rule [intro.object#2] <https://eel.is/c++draft/intro.object#2>,
>>> the
>>> > new object has became the subobject of the object X, and the condition
>>> "o1
>>> > and o2 are direct subobjects of objects P1 and P2" is true. The
>>> standard
>>> > does not say `P1` and `P2` shall not be the same object, the object
>>> > `X` itself satisfies all rules listed in [basic.life#8]
>>> > <https://eel.is/c++draft/basic.life#8>. So, there's no necessary to
>>> use
>>> > `std::launder`.
>>> >
>>> > John Mousseau via Std-Discussion <std-discussion_at_[hidden]>
>>> > 于2020年9月9日周三 上午1:49写道:
>>> >
>>> >> Dear list members,
>>> >>
>>> >> in draft N4860 <https://isocpp.org/files/papers/N4860.pdf>, which I
>>> >> assume is close to C++20, the wording of [basic.life]/8 differs from
>>> C++17
>>> >> in that the notion of "transparently replaceable" was involved. I am
>>> >> wondering whether condition 8.5 of that paragraph allows for p1 and
>>> p2 to
>>> >> be the same object.
>>> >>
>>> >> Consider the following most trivial example:
>>> >>
>>> >> struct X {int i; float f;};
>>> >> X x{3, 3.f};
>>> >> new(&x.i) int(5);
>>> >> // x.i == 5 without launder? True in C++17.
>>> >>
>>> >> According to C++17's wording this is surely the case as there is no
>>> >> const-qualification involved at all. However, in the newest wording,
>>> while
>>> >> conditions (8.1) through (8.4) are fulfilled (for o1 and o2 being the
>>> old
>>> >> and new int respectively), condition (8.5) might be unfulfilled, as
>>> neither
>>> >> are both objects complete, nor are they subobjects of (different)
>>> objects
>>> >> p1 and p2, unless, by [intro.object]/2, the new int becomes a
>>> subobject of
>>> >> x, and when then consider p1 and p2 of [basic.life]/8.5 to be
>>> identical. If
>>> >> we then consider x to be transparently-replaceable by itself, the
>>> condition
>>> >> would be fulfilled. Is that the intended interpretation or is the
>>> intention
>>> >> that the access in my example now requires std::launder even though no
>>> >> constness is involved?
>>> >>
>>> >> Sorry in case I am not seeing the obvious and thank you for your time.
>>> >>
>>> >> Best Regards
>>> >> John Mousseau
>>> >> --
>>> >> Std-Discussion mailing list
>>> >> Std-Discussion_at_[hidden]
>>> >> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>> >>
>>> >
>>> >
>>>
>>

Received on 2020-09-11 00:42:32