C++ Logo


Advanced search

Re: Casting pointers in constant evaluation

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Wed, 6 Oct 2021 20:24:14 -0400
On Wed, Oct 6, 2021 at 3:52 PM Keenan Horrigan via Std-Discussion
<std-discussion_at_[hidden]> wrote:
> > `reinterpret_cast` isn't good. It's a dangerous tool that we sometimes need, but its use should be contained. We shouldn't shove it into constexpr code just so that we can implement parts of the standard library in pure C++.
> First of all, not all my use cases for reinterpret_cast in constexpr are for implementing the standard library. I would probably doubt that the committee would find those use cases compelling, but they exist. Second, I'd agree that yes reinterpret_cast should in most cases not be used, however, as you said, it is something we sometimes need. Furthermore, the compiler would be required to detect the uses of reinterpret_cast that eventually lead to UB, so in constexpr code it would be necessarily safe on that front.

No, the compiler would be required to detect the uses of pointers that
*are UB*, not the things that led up to them. Given this code:

auto *pA = new A;
auto *pB = reinterpret_cast<B*>(pA);

The compiler would be required to realize that `pB` is "a pointer of
type `B` which points to an object of type `A`." Every piece of code
that uses pointers would have to check to see if the pointer points to
an object of the type it claims to point to. And it would only be
permitted to consider the code ill-formed if someone uses that pointer
in the wrong way.

Or we could just not have reinterpret_cast at compile-time.

> > That's how `reinterpret_cast` on pointers is *defined*. If you allowed this, then you would be allowing `reinterpret_cast`.
> Interesting, I did not not know that. I checked and it's actually only defined to have the same *result* as static_casting to and from a void pointer when converting between object pointers, but that's the case we're talking about here.
> > But why would you need to do that? Why can't you just get the address of the active member? The code would then actually make sense.
> I tried this, but it turns out it doesn't work for what I need. I need an array of uninitialized objects, and wrapping an object with a union is the only way to ensure an uninitialized object in the language as far as I know. When allocating an array of unions and then getting a pointer to the member, the constexpr interpreter treats it as a pointer to a single object when I need it as a pointer to contiguous objects. And again, as far as I can tell, this behavior is well-defined in the standard at runtime.

It treats it as a single object because it *is* a single object.

Arithmetic on pointers to type `T` is based on having an array of type
`T` ([expr.add]/4). There is no valid mechanism to have a pointer to a
direct subobject of one object and doing pointer arithmetic to get a
pointer to a direct subobject of a *different* object, if the direct
outer object in question is not an array.

Yes, your code will (probably) work at runtime. But it is *definitely*
UB and allowing reinterpret_cast at compile time will only net you a
compile error when you try it.

If you want an array of uninitialized `T`s, for a type `T` which
*supports* being uninitialized, you can do `new T[size]`. Note that
"uninitialized" is different from "there isn't an object there". If
`T` does not support being uninitialized, then it is not possible to
create an uninitialized `T`, let alone an array thereof.

> The pointer of a union is pointer-interconvertible to a pointer to one of its non-static data members. I would try to put the array inside the union, but I need a runtime length for the array, so that's not gonna work either.
> While I would certainly enjoy more STL "wrappers" for reinterpret_cast's legitimate uses, the standardization process is slow, imperfect, and doesn't cater to every individual's needs. So allowing users to reinterpret_cast on their own in constexpr and the compiler ensuring that their code is well-defined would allow developers to take advantage of those well-defined use cases without the need to wait for the committee to standardize some magic wrapper or to just eventually reject the idea.

Received on 2021-10-06 19:24:29