Date: Sat, 11 Apr 2020 01:29:41 +0900 (JST)
On Fri, Apr 10, 2020 at 10:28 PM Tadeus Prastowo 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?
Thank you for your reply. Here is an example.
[ Example:
#include <cstdlib>struct B { virtual void f(); void mutate(); virtual ~B();};struct D1 : B { void f(); };struct D2 : B { void f(); };void B::mutate() { new (this) D2; // reuses storage — ends the lifetime of *this f(); // undefined behavior ... = this; // OK, this points to valid memory}void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); *pb; // OK: pb points to valid memory void* q = pb; // OK: pb points to valid memory pb->f(); // undefined behavior, lifetime of *pb has ended} — 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.
>> 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,
merukun1125
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?
Thank you for your reply. Here is an example.
[ Example:
#include <cstdlib>struct B { virtual void f(); void mutate(); virtual ~B();};struct D1 : B { void f(); };struct D2 : B { void f(); };void B::mutate() { new (this) D2; // reuses storage — ends the lifetime of *this f(); // undefined behavior ... = this; // OK, this points to valid memory}void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); *pb; // OK: pb points to valid memory void* q = pb; // OK: pb points to valid memory pb->f(); // undefined behavior, lifetime of *pb has ended} — 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.
>> 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,
merukun1125
Received on 2020-04-10 11:32:37