This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4282. Imprecise Throws: clause in std::relocate

Section: 20.2.6 [obj.lifetime] Status: New Submitter: Giuseppe D'Angelo Opened: 2025-06-23 Last modified: 2025-06-28

Priority: Not Prioritized

View other active issues in [obj.lifetime].

View all other issues in [obj.lifetime].

View all issues with New status.

Discussion:

The current specification of std::relocate in 20.2.6 [obj.lifetime] says

Throws: Nothing.

This is imprecise. A trivially relocatable type may feature a throwing move constructor (or a throwing destructor); for instance, a linked-list implementation with an externally allocated sentinel node may have a throwing move constructor, but still be trivially relocatable. Such a type is nothrow relocatable (as per is_nothrow_relocatable_v, cf. 21.3.5.4 [meta.unary.prop]) and therefore one can call std::relocate on objects of that type.

During constant evaluation, a call to std::relocate is specified to relocate objects via move construction and destruction. (std::trivially_relocate is unavailable during constant evaluation.)

Since P3068 we are allowed to throw during constant evaluation, and therefore it's unclear whether std::relocate should propagate such an exception to the caller or should instead make the evaluation not a constant expression (and therefore make the program ill-formed, since by construction we end up in this possibility during constant evaluation).

Given the rationale brought forward for std::relocate in P2786 is to be always a nofail operation, I'm proposing a resolution that goes in that direction.

Proposed resolution:

This wording is relative to N5008.

  1. Modify 20.2.6 [obj.lifetime] as indicated:

    template<class T>
      constexpr T* relocate(T* first, T* last, T* result);
    

    -16- Mandates: […]

    -17- Preconditions: […]

    -18- Effects: […]

    -19- Returns: result + (last - first).

    -20- Throws: Nothing.

    -?- Remarks: If relocate is called during constant evaluation, and an exception is thrown by a constructor or destructor of T, the call to relocate is not a core constant expression (7.7 [expr.const]).

    [Note 3: Overlapping ranges are supported. — end note]