C++ Logo

STD-DISCUSSION

Advanced search

Subject: Re: About the description of [basic.life]/6
From: Tadeus Prastowo (tadeus.prastowo_at_[hidden])
Date: 2020-04-10 18:34:46


On Fri, Apr 10, 2020 at 6:29 PM <merukun1125_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

-- 
Best regards,
Tadeus

STD-DISCUSSION list run by std-discussion-owner@lists.isocpp.org

Older Archives on Google Groups