Created on 2025-06-23.00:00:00 last changed 4 days ago
Proposed resolution:
This wording is relative to N5008.
Modify [obj.lifetime] as indicated:
[Drafting note: For the general part of the issue (all objects in the range must be of trivially relocatable type), we append another point at the end of the existing Preconditions: element of `trivially_relocate`.
For the specifics of polymorphic types, we amend at the end of the description the existing Remarks: element]
template<class T> T* trivially_relocate(T* first, T* last, T* result);-9- Mandates: […]
-10- Preconditions:
(10.1) — `[first, last)` is a valid range.
(10.2) — `[result, result + (last - first))` denotes a region of storage that is a subset of the region reachable through `result` ([basic.compound]) and suitably aligned for the type `T`.
(10.3) — No element in the range `[first, last)` is a potentially-overlapping subobject.
(10.?) — All objects whose storage is being provided for ([intro.object]) by objects in the `[first, last)` range are of trivially relocatable type.
-11- Postconditions: […]
-12- Returns: `result + (last - first)`. -13- Throws: Nothing. -14- Complexity: Linear in the length of the source range. -15- Remarks: The destination region of storage is considered reused ([basic.life]). No constructors or destructors are invoked. If any polymorphic object ([class.virtual]) exists in storage provided for ([intro.object]) by objects in the `[first, last)` range, it is implementation-defined whether the behavior is undefined. [Note 2: Overlapping ranges are supported. — end note]
In [obj.lifetime] the `std::trivially_relocate` function is missing a precondition, that is, that any object alive in the range being relocated is itself trivially relocatable.
We know the objects in the range are trivially relocatable, because there is a Mandates: element for this. The current draft has precise rules to determine whether a type is trivially relocatable or not; in general, subobjects are considered there (cf. [class.prop], "eligible for trivial relocation", which discusses base classes and non-static data members). However these rules do not take into account objects with dynamic lifetime whose storage is being provided by (sub)objects in the range. For instance, given a `wrapper` type like:// wraps a T template<typename T> struct wrapper { alignas(T) std::byte data[sizeof(T)]; };
then one can build a non-trivially relocatable object into `wrapper` objects:
struct NTR { ~NTR() {} }; static_assert(not std::is_trivially_relocatable_v<NTR>); using WS = wrapper<NTR>; static_assert(std::is_trivially_relocatable_v<WS>); // OK
And now one can do this:
WS* ws = /* … */; // create a wrapper new (&ws->data) NTR(); // create a NTR object into it std::trivially_relocate(ws, ws+1, dest); // should be UB
Attempting to trivially relocate `*ws` should result in undefined behavior because `NTR` isn't trivially relocatable. I don't believe that this fact is correctly captured by the preconditions of `std::trivially_relocate`.
A similar issue is present for polymorphic types. In P2786's design polymorphic types can be trivially relocatable (assuming all the other conditions hold). Given a trivially relocatable polymorphic type `P`, then this code:struct P { virtual void f(); }; static_assert(std::is_trivially_relocatable_v<P>); using WP = wrapper<P>; WP* wp = /* … */; // create a wrapper new (&wp->data) P(); // create a P object into it std::trivially_relocate(wp, wp+1, dest); // implementation defined
is well-defined or UB, depending on the implementation. This is because on some implementations trivially relocating a polymorphic type requires patching its virtual table pointer; cf. the discussion in chapter 15.1 of P2786R13. However the "type erasure" done by wrapper<P> in the example (ultimately, it is just an array of bytes) does not allow implementations to do such patching, and the code is going to fail at runtime. Therefore this case also needs to be discussed by `std::trivially_relocate`'s specification.
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-06-28 14:45:08 | admin | set | messages: + msg14871 |
2025-06-23 00:00:00 | admin | create |