Bug 1884268 Comment 6 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

Hmm, https://eel.is/c++draft/basic.life#5 includes the curious language 

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
This would seem to contradict the new, clearer language about not needing to invoke the destructor, still making the reported code UB.
Hmm, https://eel.is/c++draft/basic.life#5 includes the curious language 

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
This would seem to qualify the new, clearer language about not needing to invoke the destructor, still making the reported code UB, as you can omit the destructor call only when "reusing or releasing the storage as described above".
Hmm, https://eel.is/c++draft/basic.life#5 includes the curious language 

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
This would seem to qualify the new, clearer language about not needing to invoke the destructor, still making the reported code UB, as you can omit the destructor call only when "reusing or releasing the storage as described above". The example, though, would presumably be UB anyway, because it uses `x.m` to initialize a new object in the same location, but `x.m` is indeterminate at the time the `S` initializer is called.
Hmm, https://eel.is/c++draft/basic.life#5 includes the curious language 

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
This would seem to qualify the new, clearer language about not needing to invoke the destructor, still making the reported code UB, as you can omit the destructor call only when "reusing or releasing the storage as described above". The example, though, would presumably be UB anyway, because it uses `x.m` to initialize a new object in the same location, but `x.m` is indeterminate at the time the `S` initializer is called. This sure is confusing.
> By my reading, simply leaking an object with a non-trivial destructor [by reinitializing the object with placement new] is not currently UB.

I think you're probably correct. This usage is very ugly, though, and definitely creates UB on self-assignment:

https://eel.is/c++draft/basic.life#5:

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
> By my reading, simply leaking an object with a non-trivial destructor [by reinitializing the object with placement new without previously calling the destructor] is not currently UB.

I think you're probably correct. This usage is very ugly, though, and definitely creates UB on self-assignment:

https://eel.is/c++draft/basic.life#5:

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```
> By my reading, simply leaking an object with a non-trivial destructor [by reinitializing the object with placement new without previously calling the destructor] is not currently UB.

I think you're probably correct. This usage is very ugly, though, and definitely invokes UB on self-assignment:

https://eel.is/c++draft/basic.life#5:

```
 The lifetime of an object o of type T ends when:...(1.5) the storage which the object
occupies is released, or is reused by an object that is not nested within o ([intro.object]).

When evaluating a new-expression, storage is considered reused after it is
returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).
[Example 1: struct S {
  int m;
};

void f() {
  S x{1};
  new(&x) S(x.m);   // undefined behavior
}
— end example]
```

Back to Bug 1884268 Comment 6