Discussion:
End of lifetime
(too old to reply)
r***@gmail.com
2018-02-09 21:58:16 UTC
Permalink
The first paragraph of [basic.life] <http://eel.is/c++draft/basic.life#1>
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
But let us consider the following situation:


class B{
public:
virtual void f(){ }
};

class D: public B{
public:
virtual void f(){ }
};


D d;
B* pb = &d;
new (pb) B;

In [intro.object] <http://eel.is/c++draft/intro.object> it is said that a
base class subobject is a subobject, and a subobject is considered to be
nested.
Therefore the B class subobject is nested within the object "d", therefore
the lifetime of "d" should not end.
However, the virtual table pointer of the B class subobject is now
overwritten. Here
<https://wandbox.org/nojs/gcc-head/permlink/1pF8eaeoZnn7WOVP> is this exact
example in action.

Did I miss anything from the standard?

Thank you.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2018-02-09 22:08:30 UTC
Permalink
Post by r***@gmail.com
The first paragraph of [basic.life] <http://eel.is/c++draft/basic.life#1>
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said that a
base class subobject is a subobject, and a subobject is considered to be
nested.
Therefore the B class subobject is nested within the object "d", therefore
the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life] said:
"reused *by* an object that is not nested with o".

While `d::B` is certainly nested within `d`, the *new object* you create
with `new` is not, as defined in [intro.object]/4:

An object a is nested within another object b if:
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.

In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus, `d`'s
lifetime has ended.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-09 22:19:38 UTC
Permalink
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage of
"o"?
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life] <http://eel.is/c++draft/basic.life#1>
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said that
a base class subobject is a subobject, and a subobject is considered to be
nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you create
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus, `d`'s
lifetime has ended.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-09 22:38:34 UTC
Permalink
I thought of an example.
Considering the following:

class A{};

class X{
unsigned char mem[sizeof(A)];
};

X x;
new(x.mem) A;

The new A object is nested within x.mem because x.mem provides storage for
it. Furthermore, x.mem is nested within x, as it is a class member.
Therefore the new object is nested within x, as the "nesting" relation is
transitive.

Is this correct? Are there any other examples?
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage of
"o"?
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said that
a base class subobject is a subobject, and a subobject is considered to be
nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you create
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus, `d`'s
lifetime has ended.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Smith
2018-02-10 01:08:49 UTC
Permalink
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage of
"o"?
That is described in [intro.object]p2:

"If an object is created in storage associated with a member subobject or
array element e (which may or may not be within its lifetime), the created
object is a subobject of e’s containing object if:
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location
associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."

Note that this applies to member subobjects and array elements, but *not*
to base class subobjects. The reason is that given in your question:
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said that
a base class subobject is a subobject, and a subobject is considered to be
nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you create
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus, `d`'s
lifetime has ended.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-10 09:03:31 UTC
Permalink
Ok, now I understand. So if a new object replaces some subobject of o under
the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a subobject
of o. Therefore it is nested within o. As such, the lifetime of o does not
end, because its storage was reused by a new object that is nested within
o. Thank you.

However, I have a related question. Does the standard say anything about
the following situation?

class X{};

X x;
new (&x) X;

Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only covers
cases when the lifetime of the old object already ended. I know that x's
lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage of
"o"?
"If an object is created in storage associated with a member subobject or
array element e (which may or may not be within its lifetime), the created
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location
associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but *not*
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused by *an
object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said
that a base class subobject is a subobject, and a subobject is considered
to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus, `d`'s
lifetime has ended.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Smith
2018-02-10 23:50:27 UTC
Permalink
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything about
the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only covers
cases when the lifetime of the old object already ended. I know that x's
lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of working
on P0137). I can't say for sure that the other people examining the wording
change understood that to be the intent, but I think it's really the only
natural way to combine the "lifetime ends when storage is reused" rule and
the "storage reuse of the same type allows the old name to be used to
access the new object" rule.

Another way of looking at the rule in p8 is that (excluding the weird const
/ reference cases) accessing an object only cares that there is *an* object
of the correct most-derived type in the storage, and does not care whether
it's the same object. (Although forming the access path itself may impose
additional requirements.)

Perhaps we could clarify this by changing the "The lifetime of an object o
of type T ends when" in p1 to say something like "[...] ends immediately
before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage of
"o"?
"If an object is created in storage associated with a member subobject or
array element e (which may or may not be within its lifetime), the created
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location
associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but *not*
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused
by *an object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said
that a base class subobject is a subobject, and a subobject is considered
to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus,
`d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-11 00:03:45 UTC
Permalink
Yes, if it does not affect anything else in the standard, I believe the
modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?

Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything about
the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of working
on P0137). I can't say for sure that the other people examining the wording
change understood that to be the intent, but I think it's really the only
natural way to combine the "lifetime ends when storage is reused" rule and
the "storage reuse of the same type allows the old name to be used to
access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an object o
of type T ends when" in p1 to say something like "[...] ends immediately
before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage
of "o"?
"If an object is created in storage associated with a member subobject
or array element e (which may or may not be within its lifetime), the
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location
associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused
by *an object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said
that a base class subobject is a subobject, and a subobject is considered
to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
"reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is nested
within b.
In this case, `d` does not "provide storage" for the object created by
placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus,
`d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Smith
2018-02-11 06:06:54 UTC
Permalink
Post by r***@gmail.com
Yes, if it does not affect anything else in the standard, I believe the
modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?
What I mean is for cases like this:

struct A { int x, y; };
int arr[2];
new (&arr) A;
arr[1] = 0; // UB even though there is an int at this location because the
array indexing requires an in-lifetime array object

We (probably, depending on struct layout) created two new int objects in
the storage of the two int elements of the array, but you can't use array
indexing on 'arr' to get at them because the array no longer exists.
Post by r***@gmail.com
Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything about
the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of
working on P0137). I can't say for sure that the other people examining the
wording change understood that to be the intent, but I think it's really
the only natural way to combine the "lifetime ends when storage is reused"
rule and the "storage reuse of the same type allows the old name to be used
to access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an object
o of type T ends when" in p1 to say something like "[...] ends immediately
before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage
of "o"?
"If an object is created in storage associated with a member subobject
or array element e (which may or may not be within its lifetime), the
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location
associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor ([class.dtor]
<http://eel.is/c++draft/class.dtor>), the destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is reused
by *an object that is not nested within o* ([intro.object]
<http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said
that a base class subobject is a subobject, and a subobject is considered
to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life]
said: "reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is
nested within b.
In this case, `d` does not "provide storage" for the object created
by placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus,
`d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-11 10:02:27 UTC
Permalink
The example that you showed is UB because it violates [basic.life] p7.1
<http://eel.is/c++draft/basic.life#7>, correct?
[...] the glvalue is used to access the object [...]
However, p8 <http://eel.is/c++draft/basic.life#8> assures us that the
following is legal (given that indeed the creation of A causes a new "int"
object to be created in place of arr[1]), am I right?

int* p = &(arr[1]);
new (&arr) A;
*p = 0;
Post by r***@gmail.com
Yes, if it does not affect anything else in the standard, I believe the
modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?
struct A { int x, y; };
int arr[2];
new (&arr) A;
arr[1] = 0; // UB even though there is an int at this location because the
array indexing requires an in-lifetime array object
We (probably, depending on struct layout) created two new int objects in
the storage of the two int elements of the array, but you can't use array
indexing on 'arr' to get at them because the array no longer exists.
Post by r***@gmail.com
Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything
about the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of
working on P0137). I can't say for sure that the other people examining the
wording change understood that to be the intent, but I think it's really
the only natural way to combine the "lifetime ends when storage is reused"
rule and the "storage reuse of the same type allows the old name to be used
to access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an object
o of type T ends when" in p1 to say something like "[...] ends immediately
before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the storage
of "o"?
"If an object is created in storage associated with a member subobject
or array element e (which may or may not be within its lifetime), the
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage
location associated with e, and
— the new object is of the same type as e (ignoring
cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
Post by Nicol Bolas
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor (
[class.dtor] <http://eel.is/c++draft/class.dtor>), the
destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is
reused by *an object that is not nested within o* (
[intro.object] <http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is said
that a base class subobject is a subobject, and a subobject is considered
to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life]
said: "reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is
nested within b.
In this case, `d` does not "provide storage" for the object created
by placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus,
`d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-16 08:17:20 UTC
Permalink
I apologize for insisting, I want to make sure I understand these rules.
Were my previous assumptions correct? Thank you.
Post by r***@gmail.com
The example that you showed is UB because it violates [basic.life] p7.1
<http://eel.is/c++draft/basic.life#7>, correct?
[...] the glvalue is used to access the object [...]
However, p8 <http://eel.is/c++draft/basic.life#8> assures us that the
following is legal (given that indeed the creation of A causes a new "int"
object to be created in place of arr[1]), am I right?
int* p = &(arr[1]);
new (&arr) A;
*p = 0;
Post by r***@gmail.com
Yes, if it does not affect anything else in the standard, I believe the
modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?
struct A { int x, y; };
int arr[2];
new (&arr) A;
arr[1] = 0; // UB even though there is an int at this location because
the array indexing requires an in-lifetime array object
We (probably, depending on struct layout) created two new int objects in
the storage of the two int elements of the array, but you can't use array
indexing on 'arr' to get at them because the array no longer exists.
Post by r***@gmail.com
Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything
about the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of
working on P0137). I can't say for sure that the other people examining the
wording change understood that to be the intent, but I think it's really
the only natural way to combine the "lifetime ends when storage is reused"
rule and the "storage reuse of the same type allows the old name to be used
to access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an
object o of type T ends when" in p1 to say something like "[...] ends
immediately before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the
storage of "o"?
"If an object is created in storage associated with a member
subobject or array element e (which may or may not be within its lifetime),
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage
location associated with e, and
— the new object is of the same type as e (ignoring
cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
On Friday, February 9, 2018 at 4:58:16 PM UTC-5,
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor (
[class.dtor] <http://eel.is/c++draft/class.dtor>), the
destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is
reused by *an object that is not nested within o* (
[intro.object] <http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is
said that a base class subobject is a subobject, and a subobject is
considered to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life]
said: "reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is
nested within b.
In this case, `d` does not "provide storage" for the object created
by placement new (since `d` is not an array of bytes, it cannot "provide
storage" for anything). Therefore, the storage for `d` is being reused, but
it is not being *reused by* an object nested within it. And thus,
`d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Smith
2018-02-16 21:28:44 UTC
Permalink
Post by r***@gmail.com
I apologize for insisting, I want to make sure I understand these rules.
Were my previous assumptions correct? Thank you.
Post by r***@gmail.com
The example that you showed is UB because it violates [basic.life] p7.1
<http://eel.is/c++draft/basic.life#7>, correct?
[...] the glvalue is used to access the object [...]
However, p8 <http://eel.is/c++draft/basic.life#8> assures us that the
following is legal (given that indeed the creation of A causes a new "int"
object to be created in place of arr[1]), am I right?
int* p = &(arr[1]);
new (&arr) A;
*p = 0;
Yes, as far as I can see, this is valid under the current rules. (However,
it's still in an area that I would consider "dubious", and I wouldn't be
surprised if some compilers "optimize" it in undesirable ways.)
Post by r***@gmail.com
Post by r***@gmail.com
Post by r***@gmail.com
Yes, if it does not affect anything else in the standard, I believe the
modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?
struct A { int x, y; };
int arr[2];
new (&arr) A;
arr[1] = 0; // UB even though there is an int at this location because
the array indexing requires an in-lifetime array object
We (probably, depending on struct layout) created two new int objects in
the storage of the two int elements of the array, but you can't use array
indexing on 'arr' to get at them because the array no longer exists.
Post by r***@gmail.com
Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of o
under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything
about the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of
working on P0137). I can't say for sure that the other people examining the
wording change understood that to be the intent, but I think it's really
the only natural way to combine the "lifetime ends when storage is reused"
rule and the "storage reuse of the same type allows the old name to be used
to access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an
object o of type T ends when" in p1 to say something like "[...] ends
immediately before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the
storage of "o"?
"If an object is created in storage associated with a member
subobject or array element e (which may or may not be within its lifetime),
— the lifetime of e’s containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage
location associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
On Friday, February 9, 2018 at 4:58:16 PM UTC-5,
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor (
[class.dtor] <http://eel.is/c++draft/class.dtor>), the
destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is
reused by *an object that is not nested within o* (
[intro.object] <http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is
said that a base class subobject is a subobject, and a subobject is
considered to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life]
said: "reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object* you
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is
nested within b.
In this case, `d` does not "provide storage" for the object
created by placement new (since `d` is not an array of bytes, it cannot
"provide storage" for anything). Therefore, the storage for `d` is being
reused, but it is not being *reused by* an object nested within
it. And thus, `d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
r***@gmail.com
2018-02-16 22:25:58 UTC
Permalink
Ok, I understand. Thank you very much for your help!
Post by Richard Smith
Post by r***@gmail.com
I apologize for insisting, I want to make sure I understand these rules.
Were my previous assumptions correct? Thank you.
Post by r***@gmail.com
The example that you showed is UB because it violates [basic.life] p7.1
<http://eel.is/c++draft/basic.life#7>, correct?
[...] the glvalue is used to access the object [...]
However, p8 <http://eel.is/c++draft/basic.life#8> assures us that the
following is legal (given that indeed the creation of A causes a new "int"
object to be created in place of arr[1]), am I right?
int* p = &(arr[1]);
new (&arr) A;
*p = 0;
Yes, as far as I can see, this is valid under the current rules. (However,
it's still in an area that I would consider "dubious", and I wouldn't be
surprised if some compilers "optimize" it in undesirable ways.)
Post by r***@gmail.com
Post by r***@gmail.com
Post by r***@gmail.com
Yes, if it does not affect anything else in the standard, I believe
the modification that you propose would clarify this situation.
Hopefully just one last question, what exactly are you referring to by
"(Although forming the access path itself may impose additional
requirements.)"? Is it related to how you must use "std::launder" in
special cases?
struct A { int x, y; };
int arr[2];
new (&arr) A;
arr[1] = 0; // UB even though there is an int at this location because
the array indexing requires an in-lifetime array object
We (probably, depending on struct layout) created two new int objects
in the storage of the two int elements of the array, but you can't use
array indexing on 'arr' to get at them because the array no longer exists.
Post by r***@gmail.com
Thank you very much for having the patience to answer my questions.
Post by Richard Smith
Post by r***@gmail.com
Ok, now I understand. So if a new object replaces some subobject of
o under the conditions stated in [intro.object] p2
<http://eel.is/c++draft/intro.object#2>, the new object becomes a
subobject of o. Therefore it is nested within o. As such, the lifetime of o
does not end, because its storage was reused by a new object that is nested
within o. Thank you.
However, I have a related question. Does the standard say anything
about the following situation?
class X{};
X x;
new (&x) X;
Because [basic.life] p8 <http://eel.is/c++draft/basic.life#8>only
covers cases when the lifetime of the old object already ended. I know that
x's lifetime will end when its storage is reused by the new object, however
this happens "at the same time" as the creation of the new object, not
before, therefore I do not know whether [basic.life] p8 still applies.
It was my intent that the rule would apply here (in the context of
working on P0137). I can't say for sure that the other people examining the
wording change understood that to be the intent, but I think it's really
the only natural way to combine the "lifetime ends when storage is reused"
rule and the "storage reuse of the same type allows the old name to be used
to access the new object" rule.
Another way of looking at the rule in p8 is that (excluding the weird
const / reference cases) accessing an object only cares that there is *an*
object of the correct most-derived type in the storage, and does not care
whether it's the same object. (Although forming the access path itself may
impose additional requirements.)
Perhaps we could clarify this by changing the "The lifetime of an
object o of type T ends when" in p1 to say something like "[...] ends
immediately before".
Post by r***@gmail.com
Post by Richard Smith
Post by r***@gmail.com
Thank you for your response.
So how can then an object that is nested within "o" reuse the
storage of "o"?
"If an object is created in storage associated with a member
subobject or array element e (which may or may not be within its lifetime),
— the lifetime of e’s containing object has begun and not ended,
and
— the storage for the new object exactly overlays the storage
location associated with e, and
— the new object is of the same type as e (ignoring cv-qualification)."
Note that this applies to member subobjects and array elements, but
in-place replacement of a base class subobject does not necessarily
preserve the value of the enclosing complete object. (This is not limited
to the vptr -- the tail padding of base class subobjects can be reused by
derived classes, and when that happens, reinitializing a base class
subobject can overwrite the value of derived class members.)
Post by r***@gmail.com
On Friday, February 9, 2018 at 4:58:16 PM UTC-5,
Post by r***@gmail.com
The first paragraph of [basic.life]
- (1.3) <http://eel.is/c++draft/basic.life#1.3>
if T is a class type with a non-trivial destructor (
[class.dtor] <http://eel.is/c++draft/class.dtor>), the
destructor call starts, or
- (1.4) <http://eel.is/c++draft/basic.life#1.4>
the storage which the object occupies is released, or is
reused by *an object that is not nested within o* (
[intro.object] <http://eel.is/c++draft/intro.object>).
<http://eel.is/c++draft/basic.life#1.4.sentence-1>
class B{
virtual void f(){ }
};
class D: public B{
virtual void f(){ }
};
D d;
B* pb = &d;
new (pb) B;
In [intro.object] <http://eel.is/c++draft/intro.object> it is
said that a base class subobject is a subobject, and a subobject is
considered to be nested.
Therefore the B class subobject is nested within the object "d",
therefore the lifetime of "d" should not end.
Yes, `d::B` is nested within `d`. But remember what [basic.life]
said: "reused *by* an object that is not nested with o".
While `d::B` is certainly nested within `d`, the *new object*
- a is a subobject of b, or
- b provides storage for a, or
- there exists an object c where a is nested within c, and c is
nested within b.
In this case, `d` does not "provide storage" for the object
created by placement new (since `d` is not an array of bytes, it cannot
"provide storage" for anything). Therefore, the storage for `d` is being
reused, but it is not being *reused by* an object nested within
it. And thus, `d`'s lifetime has ended.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it,
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Language Lawyer
2018-09-15 23:52:17 UTC
Permalink
Post by Richard Smith
Perhaps we could clarify this by changing the "The lifetime of an object o
of type T ends when" in p1 to say something like "[...] ends immediately
before".
I think it would be better to clarify when the reuse of a storage begins.
For objects with constructors, I suspect it is started to be reused when
the execution of a constructor starts.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Continue reading on narkive:
Loading...