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