Any useful difference between std::bit_cast and std::start_lifetime_as?
Asked Answered
R

2

15

std::bit_cast is apparently being introduced in c++20. and std::start_lifetime_as is proposed for c++23 (from P0593R5). As they appear to both require that the datatypes involved be trivial anyways, will there be any need for the former once the latter is introduced?

Reiterate answered 6/10, 2019 at 3:38 Comment(3)
You mean, besides the fact that one of them exists as a fully adopted part of the C++20 working draft, while the other is a proposal which is in flux, not adopted as part of any standard, and thus may never be standard?Beora
@NicolBolas start_lifetime_as is proposed for C++23, afaik.Reiterate
@NicolBolas Added link to it.Greenstone
R
28

The answer is trivial: bit_cast returns a value, whereas start_lifetime_as “alters” memory (in a way that exists in the abstract machine but is not expected to affect any physical bits). You use the former to (once) interpret an existing object as a set of bits; you use the latter to (permanently) interpret existing bits as an object.

Ribald answered 6/10, 2019 at 5:18 Comment(4)
Does the lifetime of the source object end after start_lifetime_as execution end? If so, trying to refer (mention) with the old pointer variable is ill-formed or only accessing is ill-formed?Restive
@sandthorn: The lifetime of any object whose storage overlaps the new object's storage ends ([basic.life]/1.5) unless the new object is nested within it (either because you recreated a subobject exactly or because a storage array was involved: [intro.object]/4). Pointers to out-of-lifetime objects have special rules ([basic.life]/6).Ribald
If the new start_lifetime_as only depends on UB lifetime rules like that, it is kind of scary. [LIVE] That is the compiler can't help one who might forget the lifetime rules. It would be more secure if start_lifetime_as could invoke ill-formed when misused.Restive
@sandthorn: If it were possible to implement that, we wouldn't need the function in the first place.Ribald
O
16

std::bit_cast copies the bits of its argument to a new value of a different type.

float myFloat = 3.14;
auto asUint = std::bit_cast<uint32_t>(myFloat);
auto asBytes = std::bit_cast<std::array<char,4>>(myFloat);

myFloat, asUint and asBytes are separate variables with separate addresses. The compiler may be able to optimise some them away completely, but logically they are completely distinct values that just happen to have the same size and bits.

std::start_lifetime_as doesn't do anything. It just informs the compiler that it can treat a range of memory as if it contained an array of the specified type. This then allows the developer to use that memory as an array without triggering undefined behaviour. It doesn't physically modify the memory passed to it and it doesn't return anything. It's purely for C++ object model bookkeeping.

Edit: Robert Leahy has an excellent presentation explaining the problems these functions were created to solve and how they are implemented.

Oliverolivera answered 11/10, 2019 at 11:47 Comment(1)
Would this mean that, for instance, if there was a union of two trivial types of identical size where the bit patterns for one is a valid bit pattern for the other, that you can assign one member of the union, invoke std::start_lifetime_as on the union instance it for the other type, and then access it from the second member without UB?Reiterate

© 2022 - 2024 — McMap. All rights reserved.