Why does a nested array object prevent providing storage?
Asked Answered
T

1

6

At Lifetime under Providing storage, it says:

As a special case, objects can be created in arrays of unsigned char or std::byte (since C++17) (in which case it is said that the array provides storage for the object) if

  • the lifetime of the array has begun and not ended
  • the storage for the new object fits entirely within the array
  • there is no array object that satisfies these constraints nested within the array.

Why is the third condition there?

Even if there's a nested array (I believe it means an array which starts at some index of the outer array and ends at an index that's no farther, not an array which is an item of the outer array, as the term nested would probably be understood in most languages), what difficulty does it pose to the standard authors or implementations to enable a segment of the outer array disjoint with the nested array to provide storage?

And, if the nested array doesn't have any array nested in it, do I understand correctly that it can provide storage? If so, why can't the outer array provide storage in the same place, i.e. with the segment providing storage not straddling the start or end of any nested (perhaps indirectly) array?

And, even with straddling, what problems could arise that the standard included this requirement to avoid?

Additionally, can a nested array not satisfy the second condition, i.e. overlap it partially? Can such arrays even exist? In what sense and under ehat conditions is then one nested in another? Can both ever be nested in each other?

Tithing answered 20/7, 2023 at 4:33 Comment(2)
Have you seen cplusplus.github.io/CWG/issues/2470.html?Decurved
I have now, thanks!Tithing
S
5

Consider this example (ignoring alignment)

struct A { std::byte s2[64]; };
std::byte s1[128];
int* i1 = new(s1) int;
A* a = new(s1 + 32) A; // Create at some valid offest
int* i2 = new(a->s2) int;

If we go by the quote you brought, both s1 and a->s2 satisfy the first and second bullet with regard to the integer i2 we created. However, I think we can all agree that it would be more precise to identify a->s2 as providing the storage, since it contains our integer more snuggly (while s1 provides storage for i1). The third bullet does exactly that, i.e. it identifies the "nearest" array object that provides the storage for an object.

A nested array cannot be one that "starts at some index", because it won't be an array at all. Arrays under the C++ standard are objects with a specific type (size information is baked into them), and shifting the start or end point won't magically create and array in the region (technically we can reinterpret_cast the region, but that quickly has us courting undefined behavior so I wouldn't consider it pertinent to the discussion).

Setaceous answered 20/7, 2023 at 4:42 Comment(7)
So it's meant to pare the relation of providing storage down by transitive reduction?Tithing
@Tithing - Indeed, well put.Setaceous
Now it's clear, thanks! So it seems I got confused by the wording at cppreference.com. I thought it prohibited there being a nested array anywhere in the same outer array, even if it doesn't overlap with the created object.Tithing
And the line char *d = new (au.data + 1) char(); there causes UB unless (which happens to be true on most implementations) int is wider than char, right?Tithing
@Tithing - Yes, correct again. I glossed over the fact that multiple objects can be created in the same array, so long as size permits (but my own example now touches on that too).Setaceous
To be still more precise: I think UB is impossible when sizeof(int) > 1 and possible but not guaranteed otherwise. Not guaranteed because implementation can include arbitrary padding in the representation of AlignedUnion.Tithing
@Tithing - No, it would be guaranteed. Yes there may be padding, but it's not part of the array data. So the array cannot provide storage. In practice, this allows compilers to instrument that padding somehow, and makes an access trap when the padding is touched (this is the general way memory sanitizers work).Setaceous

© 2022 - 2024 — McMap. All rights reserved.