5
struct X { int n; };
const X *p = new const X{3};  // #1
new (const_cast<X*>(p)) const X{5};  // #2
const int c = std::launder(p)->n; 

Assume that the object created at #1 is named obj1 while the object created at #2 is named obj2. The precondition of std::launder is that

[ptr.launder] p2 link

p represents the address A of a byte in memory. An object X that is within its lifetime and whose type is similar to T is located at the address A. All bytes of storage that would be reachable through the result are reachable through p (see below).

A byte of storage b is reachable through a pointer value that points to an object Y if there is an object Z, pointer-interconvertible with Y, such that b is within the storage occupied by Z, or the immediately-enclosing array object if Z is an array element.

This rule is a bit obscure. Is the following interpretation a right read?

obj2 will occupy the number of sizeof(X) bytes beginning with A. Consider Y(the object to which std::launder(p) points) and Z(namely, obj2) as the same object, they are pointer-interconvertible, and the sizeof(X) bytes occupied by obj2 are all within Z, hence these bytes are all reachable through std::launder(p). that is, "All bytes of storage that would be reachable through the result". Whether these bytes are reachable through p? With the assumption that Y (namely, the object to which p points) and Z are the same object obj1, which are also the array element of a hypothetical array, as per [basic.compound] p3

an object of type T that is not an array element is considered to belong to an array with one element of type T.

Since these bytes beginning with A are all within the array of which Z is an element. Hence, we can say these bytes are all reachable through p?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • Can you put what it is you are trying to conclude at the front of your interpretation? Like, "I would like to say BLAH". I think you are trying to say "`obj2`s bytes are reachable through `p`", but decoding your paragraph isn't easy. Too much renaming of things and pronouns. Every time you say "these", for example, I have to do a bunch of work to figure out exactly which "these" you are talking about. I could assume, but you want to know if you are right, not if what I read your words as saying is right. – Yakk - Adam Nevraumont Jan 17 '22 at 15:54
  • How [basic.compound]/3 is related? It says «For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq])», not «For any purposes» – Language Lawyer Jan 17 '22 at 15:58
  • See https://stackoverflow.com/questions/51552713/can-stdlaunder-be-used-to-convert-an-object-pointer-to-its-enclosing-array-poi – Language Lawyer Jan 17 '22 at 16:18
  • @LanguageLawyer How do you interpret the definition of "reachable through"? – xmh0511 Jan 18 '22 at 01:30
  • @Yakk-AdamNevraumont The above are all based on my opinion for how to interpret "reachable through" to make all bytes that are reachable through `std::launder(p)` can be reachable through `p`. Since the above comment points out that [basic.compound]/3 is irrelevant here. Obviously, my opinion is wrong since it's based on a false premise. Except that `obj1`(p points to) would be pointer-interconvertible with `obj2`, I cannot figure out why those bytes that are reachable through `std::launder(p)` can be reachable through `p`, according to the definition of `reachable through`. – xmh0511 Jan 18 '22 at 01:56
  • @xmh0511 as described in http://eel.is/c++draft/ptr.launder#4.sentence-2 – Language Lawyer Jan 18 '22 at 13:37
  • @LanguageLawyer Hmmm... I was not saying the pure definition of "reachable through". I just wondered how do you interpret the aforementioned example through the current definition of "reachable through". – xmh0511 Jan 18 '22 at 14:13

1 Answers1

1

[basic.compound]/3 is not relevant. It specifically says that it applies only for the purpose of pointer arithmetic and comparison. There doesn't actually exist an array for the object.

I think when you call std::launder, there are four objects at the relevant address: obj1, obj1.n, obj2 and obj2.n. obj1 and obj1.n are pointer-interconvertible, as are obj2 and obj2.n. Other combinations aside from identical pairs, are not pointer-interconvertible. There are no array objects and therefore "or the immediately-enclosing array object if Z is an array element." isn't relevant.

When considering reachability from std::launder(p), which points to obj2 thus only obj2 and obj2.n need to be considered as Z in the quote. obj2.n occupies an (improper) subset of bytes of obj2, so it is not relevant. The bytes reachable are those in obj2. Except that I considered obj2.n specifically, this is a rephrasing of your considerations.

By exactly the same reasoning, the bytes reachable from p (pointing to obj1) are all those in obj1.

obj1 and obj2 have the same size and therefore occupy exactly the same bytes. Therefore std::launder(p) would not make any bytes reachable that aren't reachable from p.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • *`obj1` and `obj2` have the same size and therefore occupy exactly the same bytes. Therefore...* That's not what the definition of "reachable through" says, Isn't it? All bytes that are reachable through `std::launder(p)` is those within `obj2`, and `p` points to `obj1`, with this condition, except that `obj1` is pointer-interconvertible with `obj2`, I cannot figure out why those bytes that are reachable through `std::launder(p)` can be reachable through `p`. – xmh0511 Jan 18 '22 at 01:33
  • 1
    @xmh0511 I don't think `obj1` and `obj2` are pointer-interconvertible. The _reachable through_ definition says that any single byte is _reachable_ if one of the Z objects occupies storage containing it. Suppose `X` has size `4`. There are exactly four bytes occupied by `obj1`, starting at address `&obj1`. `obj2` also occupies exactly four bytes starting at address `&obj2`, but the two addresses are the same and therefore these four bytes of storage are exactly the same. – user17732522 Jan 18 '22 at 06:44
  • 1
    So, you mean that the definition of *reachable through* only purposes to determine which bytes a single pointer to an object can be reachable? To determine whether these bytes in two irrelevant(disjoint) objects to which the two pointers point to can be reachable through by each other, it relies on whether these bytes themself have certain relationships(e.g., the two objects contain the same bytes)? – xmh0511 Jan 18 '22 at 07:02
  • 1
    @xmh0511 The whole point of the requirement is to make sure that you can't use `std::launder` followed by `reinterpret_cast` and pointer arithmetic to access memory locations that you couldn't before, since that would impede compiler optimizations. I am not saying that the bytes occupied by the two objects have a relationship of being equal, I am saying that they are the same identical bytes. Bytes are the fundamental memory unit and objects are simply placed on top of them. https://eel.is/c++draft/basic#intro.memory-1 – user17732522 Jan 18 '22 at 07:16
  • 1
    I didn't say they *have a relationship of being equal*. I said *it relies on whether these bytes themself have certain relationships(e.g., the two objects contain the **same bytes**)*, specifically, all bytes that `A` can reach have the same address as those bytes that `B` can reach, this should be the same as what you said *《they are the same identical bytes》* – xmh0511 Jan 18 '22 at 09:55
  • 1
    @xmh0511 Then I think we agree and have the same interpretation. – user17732522 Jan 18 '22 at 10:02