Date: Fri, 10 Apr 2020 17:28:58 +0200
On Fri, Apr 10, 2020 at 4:29 PM merukun1125--- via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> Inspired by: https://teratail.com/questions/250362 and
> https://stackoverflow.com/questions/56977042/reusing-objects-space-by-another-object.
>
> At the beginning of [basic.life]/6
> <https://timsong-cpp.github.io/cppwp/n4659/basic.life#6>, the following was written:
>
> Before the lifetime of an object has started but after the storage which
> the object will occupy has been allocated or, after the lifetime of
> an object has ended and before the storage which the object occupied is reused or
> released, any pointer that represents the address of the storage location where the
> object will be or was located may be used but only in limited ways.
>
> However, the example in [basic.life]/6 also describes a pointer to the
> storage which the new object was created.
Could you copy and paste the example, please?
> 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.
> std::uint32_t lval = *p32 + 100; // (b)
UB due to `*p32' for the reason given above.
> 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.
> 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.
> }
>
> Thank you.
<std-discussion_at_[hidden]> wrote:
>
> Inspired by: https://teratail.com/questions/250362 and
> https://stackoverflow.com/questions/56977042/reusing-objects-space-by-another-object.
>
> At the beginning of [basic.life]/6
> <https://timsong-cpp.github.io/cppwp/n4659/basic.life#6>, the following was written:
>
> Before the lifetime of an object has started but after the storage which
> the object will occupy has been allocated or, after the lifetime of
> an object has ended and before the storage which the object occupied is reused or
> released, any pointer that represents the address of the storage location where the
> object will be or was located may be used but only in limited ways.
>
> However, the example in [basic.life]/6 also describes a pointer to the
> storage which the new object was created.
Could you copy and paste the example, please?
> 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.
> std::uint32_t lval = *p32 + 100; // (b)
UB due to `*p32' for the reason given above.
> 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.
> 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.
> }
>
> Thank you.
-- Best regards, Tadeus
Received on 2020-04-10 10:32:08