C++ Logo

std-discussion

Advanced search

Re: About the description of [basic.life]/6

From: merukun1125_at <merukun1125_at_[hidden]>
Date: Sat, 11 Apr 2020 11:15:54 +0900 (JST)
Thank you for your answer!

On Fri, Apr 10, 2020 at 18:34 CDT Tadeus Prastowo via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>> void g() {
>> void* p = std::malloc(sizeof(D1) + sizeof(D2));
>> B* pb = new (p) D1;
>> pb->mutate();
>> *pb; // OK: pb points to valid memory
>
> The above line is the particular point of the example that you are
> concerned about.
>
>> }
>>
>> — end example ]
>>
>> >> Does the description of [basic.life]/6, especially the description after the
>> >> "otherwise" clause, also say a pointer to the storage which another new object was created?
>> >>
>> >> Furthermore, does (a) to (f) in the following code cause undefined behavior?
>> >>
>> >> #include <cstdint>
>> >> #include <new>
>> >>
>> >> int main()
>> >> {
>> >> std::uint32_t* p32 = new std::uint32_t[4]{};
>>
>> > At this point, the four objects of type std::uint32_t have already
>> > been alive due to the use of `{}'.
>>
>> >> std::uint16_t* p16 = new (p32) std::uint16_t[4]{};
>>
>> > At this point, the four objects of type std::uint32_t have ended their
>> > lives due to storage reuse.
>> > And, the four objects of type std::uint16_t have already been alive
>> > due to the use of `{}'.
>>
>> >> *p32; // (a) (indirect references of type void* are not allowed)
>>
>> > UB because the four objects of type std::uint32_t have ended their
>> > lives due to storage reuse.
>>
>> In the [basic.life]/6 example, I do not know why `*pb` is not UB.
>
> Thanks for pointing that out. Now I would like to revise my answers.
>
> This is not UB, including the example's *pb, because:
> [basic.lval]/1.4 "An lvalue is a glvalue that is not an xvalue."
> [basic.life]/6 "Indirection through such a pointer is permitted but
> the resulting lvalue may only be used in limited ways, as described
> below."
> [basic.life]/7 "using the properties of the glvalue that do not depend
> on its value is well-defined"
>
>> >> std::uint32_t lval = *p32 + 100; // (b)
>>
>> > UB due to `*p32' for the reason given above.
>
> UB because the expression *p32 + 100 is "using the properties of the
> glvalue that [depend] on its value".
>
>> >> std::uint32_t* p32_2 = p32 + 2; // (c)
>>
>> > This is okay because p32 is a valid pointer.
>>
>> >> *p32_2 = 0; // (d)
>>
>> > UB for the same reason `*p32' is UB.
>
> UB because, quoting [basic.life]/7.1, "the glvalue is used to access
> the object".
>
>> >> p32 = new (p32) std::uint32_t[4]; // (e)
>>
>> > At this point, the four objects of type std::uint16_t have ended their
>> > lives due to storage reuse.
>> > The four objects of type std::uint32_t, however, have not been
>> > constructed due to missing `{}'.
>>
>> >> delete [] p32; // (f)
>>
>> > This deallocates the storage. Not UB because std::uint32_t has no
>> > non-trivial destructor.
>
> This one is already correct based on [basic.life]/6.1
>

--
Best regards,
merukun1125

Received on 2020-04-10 21:18:49