Date: Thu, 10 Jul 2025 18:28:30 -0400
On Thu, Jul 10, 2025 at 5:57 PM Ell via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> If an array provides storage for an object, does destroying the object
> "invalidate" the contents of the array?
>
> void f () {
> unsigned char a[1];
>
> using T = unsigned char;
>
> T* p = new (a) T (123);
> unsigned char x = a[0];
> p->~T ();
>
> unsigned char y = a[0];
>
> assert (x == y);
> }
>
In this case, we have to answer the question of whether the newly created
object is an element of the array, or whether the original element is still
there and the array is providing storage for the new object.
[intro.object]/2 <http://eel.is/c++draft/intro.object#2> states that the
new object in this particular case is a subobject of the array `a`.
Presumably an array cannot have two elements with index 0, so we can infer
that the original `a[0]`'s lifetime ends as in [basic.life]/2.5
<http://eel.is/c++draft/basic.life#2.5>. The array doesn't provide storage
for the new `unsigned char` object. When the new object is later destroyed,
`a[0]` is out-of-lifetime and attempting to access its value results in UB.
If you had created an object of some other type, say, `char`, in the
storage of `a`, the standard is unclear as to what happens to the value of
`a[0]` in that case (either during or after the `char` object's lifetime).
>
> The assert passes using clang (and msvc), but not gcc with optimizations
> on. Is gcc doing the "right thing" here? Is this UB? EB?
>
> I'm mostly asking because of how this affects types like vector:
>
> auto f (std::vector<std::unique_ptr<int>>& v) {
> auto x = std::move (v.back ());
>
> v.pop_back ();
>
> return x;
> }
>
> Here clang bothers to zero out the moved-from unique_ptr, even though it
> knows the subsequent destructor is a nop, while gcc doesn't [1].
> Obviously (?), gcc's behavior is preferable, but is it correct?
>
> [1] https://godbolt.org/z/b663K1bnd
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
std-discussion_at_[hidden]> wrote:
> If an array provides storage for an object, does destroying the object
> "invalidate" the contents of the array?
>
> void f () {
> unsigned char a[1];
>
> using T = unsigned char;
>
> T* p = new (a) T (123);
> unsigned char x = a[0];
> p->~T ();
>
> unsigned char y = a[0];
>
> assert (x == y);
> }
>
In this case, we have to answer the question of whether the newly created
object is an element of the array, or whether the original element is still
there and the array is providing storage for the new object.
[intro.object]/2 <http://eel.is/c++draft/intro.object#2> states that the
new object in this particular case is a subobject of the array `a`.
Presumably an array cannot have two elements with index 0, so we can infer
that the original `a[0]`'s lifetime ends as in [basic.life]/2.5
<http://eel.is/c++draft/basic.life#2.5>. The array doesn't provide storage
for the new `unsigned char` object. When the new object is later destroyed,
`a[0]` is out-of-lifetime and attempting to access its value results in UB.
If you had created an object of some other type, say, `char`, in the
storage of `a`, the standard is unclear as to what happens to the value of
`a[0]` in that case (either during or after the `char` object's lifetime).
>
> The assert passes using clang (and msvc), but not gcc with optimizations
> on. Is gcc doing the "right thing" here? Is this UB? EB?
>
> I'm mostly asking because of how this affects types like vector:
>
> auto f (std::vector<std::unique_ptr<int>>& v) {
> auto x = std::move (v.back ());
>
> v.pop_back ();
>
> return x;
> }
>
> Here clang bothers to zero out the moved-from unique_ptr, even though it
> knows the subsequent destructor is a nop, while gcc doesn't [1].
> Obviously (?), gcc's behavior is preferable, but is it correct?
>
> [1] https://godbolt.org/z/b663K1bnd
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
-- *Brian Bi*
Received on 2025-07-10 22:28:44