Jump to Table of Contents Collapse Sidebar

PxxxxR0
consteval int relocatability

Draft Proposal,

Author:
Thomas PK Healy (healy8tpk@vir8jacode.com -- Remove all 8's)
Audience:
SG16
Project:
ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21

Abstract

Remove all mentions of "trivially relocatable" from the C++ Standard and replace with an integer rating for relocatability.

1. Introduction

There is ongoing disagreement and confusion around the phrase "trivially relocatable", as some C++ programmers intuitively think that it should mean that T can relocated by simply doing a raw byte-by-byte copy from one memory location to another (for example by using memcpy, memmove, realloc or a simple loop with char unsigned pointers).

This proposal removes the phrase "trivially relocatable" from the Standard and replaces it with an integer rating for relocatability. The following consteval template function shall be added to the standard library:

namespace std {
    template<typename T>
    consteval int relocatability(void) noexcept
    {
        . . .
    }
}

The integer returned from this function can have eleven possible values:

 0 : cannot relocate
 1 : relocate by memcpy/memmove
 2 : relocate by implementation-specific built-in compiler algorithm that never throws
 3 : relocate by static member function belonging to class (e.g.T::_Relocate) that never throws
-3 : relocate by static member function belonging to class (e.g.T::_Relocate) that might throw
 4 : relocate by nothrow-move and destroy
-4 : relocate by move (might throw) and destroy
 5 : relocate by nothrow-copy and destroy
-5 : relocate by copy (might throw) and destroy
 6 : relocate by nothrow-default-construction and nothrow-assignment and destroy
-6 : relocate by default-construction (might throw) and assignment (might throw) and destroy

2. Motivation

Papers such as P3780 (Giuseppe D’Angelo) illustrate ongoing disagreement within the committee about the precise semantics of "trivial relocation". Some committee members feel that 'trivial' should mean that we can memcpy the object’s bytes, while other committee members allow for the invocation of implementation-specific relocation algorithms (for example on the arm64e architecture, the re-signing of vtable pointers). These differing views hinder standardisation.

A numeric classification removes ambiguity by explicitly stating how a type can be relocated, instead of a binary yes/no notion.

3. Proposed API

namespace std {
    template<typename T>
    consteval int relocatability(void) noexcept
    {
        . . .
    }
}

4. Custom-implemented Relocator

Here is an example of a class which provides its own reallocation algorithm:

struct File {
    int fd = -1;
    unsigned long relocation_count = 0u;
    ...
    ...
    File(void  ) = default;
    File(File& ) = delete;
    File(File&&) = delete;
    static void _Relocate(File *const dest, File const *const src, std::size_t const n) noexcept
    {
        std::memcpy( dest, src, n * sizeof(*dest) );
        . . .
        . . .
        for ( std::size_t i = 0u; i < n; ++i )
            dest[i].relocation_count += 1u;
    }
};

template<typename T>
requires ( 0 < std::relocatability<  std::remove_cvref_t<T>  >() )
void MyFunction(T &&arg)
{
    // Works only for non-throwing relocatable types
}

static_assert(  3 == std::relocatability<File>()  );

int main(void)
{
    File f;
    MyFunction(f);    
}

5. Implementation

A possible implementation:

template<typename T>
consteval int relocatability(void) noexcept
{
    if constexpr ( requires(T *dst, T const *src, std::size_t n){ T::_Relocate(dst, src, n); } )
    {
        return noexcept(T::_Relocate((T*)nullptr,(T*)nullptr,1uz)) ? 3 : -3;
    }
    else if constexpr (  /* . . arm64e stuff . . */ ) return 2;
    else if constexpr ( is_trivially_copyable_v<T>  ) return 1; // memcpy/memmove
    else if constexpr ( is_destructible_v<T> )
    {
        /**/ if constexpr ( is_nothrow_move_constructible_v<T>  ) return  4;
        else if constexpr ( is_move_constructible_v<T>          ) return -4;
        else if constexpr ( is_nothrow_copy_constructible_v<T>  ) return  5;
        else if constexpr ( is_copy_constructible_v<T>          ) return -5;
        else if constexpr ( is_nothrow_default_constructible_v<T> && is_nothrow_assignable_v<T&,T> ) return 6;
        else if constexpr ( is_default_constructible_v<T> && is_assignable_v<T&, T> ) return -6;
    }
    else return 0;
}

6. Design Considerations

7. Impact on the Standard

This proposal introduces a single, header-only library extension (<type_traits>), adds no new keywords, and provides a clear replacement for the ambiguous term "trivially relocatable". It has no breaking changes -- all pre-existing code will be unaffected.