Discussion:
On "provides storage" and the "underlying" array object lifetime
(too old to reply)
Language Lawyer
2018-08-22 21:23:54 UTC
Permalink
Do I understand it correctly, that ending the lifetime of an array object which provides storage to some other object without releasing the storage does not end the lifetime of the objects it provided storage to?

If so, the "provides storage" term sounds unfortunate for me, because it suggests that ending lifetime of the array behaves as if the storage was released.
--
---
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-08-22 23:28:42 UTC
Permalink
Post by Language Lawyer
Do I understand it correctly, that ending the lifetime of an array object
which provides storage to some other object without releasing the storage
does not end the lifetime of the objects it provided storage to?
If so, the "provides storage" term sounds unfortunate for me, because it
suggests that ending lifetime of the array behaves as if the storage was
released.
I agree, but that's not new with the addition of "provides storage".
"Subobject" has the same problem. Consider this:

struct A { int x; int y; };

void f() {
A a;
int &r = a.y;
static_assert(sizeof(int) == sizeof(float));
new (&a.x) float; // by [basic.life], this ends the lifetime of a.x and
the lifetime of a, but not the lifetime of a.y, because it reuses the
storage of a and of a.x to create an object that is nested within neither
of them
r = 1; // still ok?
}

This is exactly analogous to what happens if you end the lifetime of an
array that provides storage for an object: the lifetime of the object
doesn't necessarily end.

I think this whole situation is unfortunate: the lifetime rules would seem
more sensible if ending the lifetime of an object ended the lifetime of any
object nested within it. (That way, "nested within" would indicate a subset
in both time and space, which is really what it was intended to convey.)
--
---
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-08-23 14:07:56 UTC
Permalink
Post by Richard Smith
Post by Language Lawyer
Do I understand it correctly, that ending the lifetime of an array object
which provides storage to some other object without releasing the storage
does not end the lifetime of the objects it provided storage to?
If so, the "provides storage" term sounds unfortunate for me, because it
suggests that ending lifetime of the array behaves as if the storage was
released.
I agree, but that's not new with the addition of "provides storage".
struct A { int x; int y; };
void f() {
A a;
int &r = a.y;
static_assert(sizeof(int) == sizeof(float));
new (&a.x) float; // by [basic.life], this ends the lifetime of a.x and
the lifetime of a, but not the lifetime of a.y, because it reuses the
storage of a and of a.x to create an object that is nested within neither
of them
r = 1; // still ok?
}
This is exactly analogous to what happens if you end the lifetime of an
array that provides storage for an object: the lifetime of the object
doesn't necessarily end.
I think this whole situation is unfortunate: the lifetime rules would seem
more sensible if ending the lifetime of an object ended the lifetime of any
object nested within it. (That way, "nested within" would indicate a subset
in both time and space, which is really what it was intended to convey.)
The problem there is that destructors end the lifetime of a type when they
*begin* executing. That would mean that all subobjects' lifetimes would end
before their destructors are even called, thus invoking UB.

Also, I don't think the above code ends the lifetime of `a`. You're used a
pointer to `a.x`, so that's the object whose lifetime is being reused, not
`a`.
--
---
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-08-23 15:11:19 UTC
Permalink
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're used a
pointer to `a.x`, so that's the object whose lifetime is being reused, not
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement new shall have the value "pointer to an object" to end the lifetime of the object.
The wording in [intro.object] and [basic.life] suggests that there is no such intention.


But this discussion gave me an idea that it could be a defect that the placement new-expression calling non-allocating form of operator new do not have a requirement similar to std::launder's requirement: all bytes of storage that would be reachable through the result of the new-expression are reachable through the pointer argument of the placement new-expression.
--
---
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-08-23 17:40:26 UTC
Permalink
Post by Language Lawyer
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're used
a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being reused,
not
Post by Nicol Bolas
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement new
shall have the value "pointer to an object" to end the lifetime of the
object.
The wording in [intro.object] and [basic.life] suggests that there is no such intention.
And yet, the notes in [intro.object] contain the following code:

template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}

If you are correct, then `au`'s lifetime ends with the first line. Yet
`au.data` is still valid after this, even though it would clearly be
accessing an object whose lifetime has ended. Furthermore, none of the
comments say anything about the lifetime of `au` ending, even though it is
clear that `*p`'s lifetime has ended.

So it seems very much to me that while `&au` and `&au.data` will have the
same address, the intent of the specification is that reusing the storage
for `au.data` is *not* the same thing as reusing the storage for `au`
itself.
--
---
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-08-23 17:47:35 UTC
Permalink
Post by Nicol Bolas
Post by Language Lawyer
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're used
a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being reused,
not
Post by Nicol Bolas
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement new
shall have the value "pointer to an object" to end the lifetime of the
object.
The wording in [intro.object] and [basic.life] suggests that there is no such intention.
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
If you are correct, then `au`'s lifetime ends with the first line.
Lifetime of an object O ends if its storage is reused by an object that is not nested within O. (http://eel.is/c++draft/basic.life#1.4, http://eel.is/c++draft/intro.object#def:nested_within)
The int object is nested within `au.data` because `au.data` provides storage for it. And the int object is nested within `au`, because `au.data` is a subobject of `au` (therefore `au.data` is nested within `au`) and "nested within" is a transitive relation.
--
---
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/.
i***@gmail.com
2018-08-26 21:37:11 UTC
Permalink
Post by Nicol Bolas
Post by Nicol Bolas
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're
used a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being reused,
not
Post by Nicol Bolas
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement new
shall have the value "pointer to an object" to end the lifetime of the
object.
The wording in [intro.object] and [basic.life] suggests that there is no such intention.
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
If you are correct, then `au`'s lifetime ends with the first line. Yet
`au.data` is still valid after this, even though it would clearly be
accessing an object whose lifetime has ended. Furthermore, none of the
comments say anything about the lifetime of `au` ending, even though it is
clear that `*p`'s lifetime has ended.
So it seems very much to me that while `&au` and `&au.data` will have the
same address, the intent of the specification is that reusing the storage
for `au.data` is *not* the same thing as reusing the storage for `au`
itself.
Maybe standard need wording that byte array can't be destroyed when you
reuse it storage? This will be consequence of current rule that allow you
to access any memory using `std::byte` pointer.

Another point, if we have `struct X { int x; int y; } a;` and we reuse
storage of `a.x` then we effective destroy whole object because `a` is not
any more `X` and any use of `a.x` will cause UB.
But if we have `struct X { char data[16]; int y; } b` then we can freely
reuse `b.data` because `b` is still valid `X`.
--
---
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-08-26 22:01:33 UTC
Permalink
Post by i***@gmail.com
Post by Nicol Bolas
Post by Nicol Bolas
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're
used a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being reused,
not
Post by Nicol Bolas
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement new
shall have the value "pointer to an object" to end the lifetime of the
object.
The wording in [intro.object] and [basic.life] suggests that there is no
such intention.
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
If you are correct, then `au`'s lifetime ends with the first line. Yet
`au.data` is still valid after this, even though it would clearly be
accessing an object whose lifetime has ended. Furthermore, none of the
comments say anything about the lifetime of `au` ending, even though it is
clear that `*p`'s lifetime has ended.
So it seems very much to me that while `&au` and `&au.data` will have the
same address, the intent of the specification is that reusing the storage
for `au.data` is *not* the same thing as reusing the storage for `au`
itself.
Maybe standard need wording that byte array can't be destroyed when you
reuse it storage? This will be consequence of current rule that allow you
to access any memory using `std::byte` pointer.
There is a rule allowing one to access an object through a glvalue of std::byte type.
There is no rule enabling one to access an object through a glvalue of std::byte type.
(https://groups.google.com/a/isocpp.org/d/msg/std-discussion/JNp8xsgRbW4/HbzPHs75AwAJ)
--
---
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/.
i***@gmail.com
2018-08-26 22:25:18 UTC
Permalink
Post by Nicol Bolas
Post by i***@gmail.com
On Thursday, August 23, 2018 at 11:11:26 AM UTC-4, Language Lawyer
Post by Nicol Bolas
Post by Nicol Bolas
Also, I don't think the above code ends the lifetime of `a`. You're
used a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being
reused,
Post by i***@gmail.com
Post by Nicol Bolas
not
Post by Nicol Bolas
`a`.
The lifetime ends when (a part) of an object storage is reused.
There is no such requirement that the pointer passed to the placement
new
Post by i***@gmail.com
Post by Nicol Bolas
shall have the value "pointer to an object" to end the lifetime of the
object.
The wording in [intro.object] and [basic.life] suggests that there is
no
Post by i***@gmail.com
Post by Nicol Bolas
such intention.
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
If you are correct, then `au`'s lifetime ends with the first line. Yet
`au.data` is still valid after this, even though it would clearly be
accessing an object whose lifetime has ended. Furthermore, none of the
comments say anything about the lifetime of `au` ending, even though it
is
Post by i***@gmail.com
clear that `*p`'s lifetime has ended.
So it seems very much to me that while `&au` and `&au.data` will have
the
Post by i***@gmail.com
same address, the intent of the specification is that reusing the
storage
Post by i***@gmail.com
for `au.data` is *not* the same thing as reusing the storage for `au`
itself.
Maybe standard need wording that byte array can't be destroyed when you
reuse it storage? This will be consequence of current rule that allow
you
Post by i***@gmail.com
to access any memory using `std::byte` pointer.
There is a rule allowing one to access an object through a glvalue of std::byte type.
There is no rule enabling one to access an object through a glvalue of std::byte type.
(
https://groups.google.com/a/isocpp.org/d/msg/std-discussion/JNp8xsgRbW4/HbzPHs75AwAJ)
You are referring this to my "to access any memory using"? I used wrong
words, I mean rule that allow `memcpy` access to object data.
--
---
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-13 16:38:57 UTC
Permalink
On 23/08/18 17:07, Nicol Bolas wrote:> Also, I don't think the above code ends the lifetime of `a`. You're used a
Post by Nicol Bolas
pointer to `a.x`, so that's the object whose lifetime is being reused, not
`a`.
What's unclear is whether the new-expression constitutes a re-use of x's storage or of x.buf's storage.
If the new-expression were new (&x) A{} instead of new (x.buf) A{}, does that change anything? I can't find any Standardese that clearly differentiates the behavior of these two expressions.
I agree. The wording in [intro.object] and [basic.life] concern themselves with the storage address represented by a pointer, not the object to which it points.
--
---
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...