C++ Logo

std-proposals

Advanced search

Re: [std-proposals] is_trivially_copyable_in_reality

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Thu, 22 Jan 2026 15:48:18 +0000
On Tue, Jan 20, 2026 at 10:28 PM Frederick Virchanza Gotham wrote:
> >
> > All polymorphic classes in C++ are deemed to be "not trivially
> > copyable" . . . even though the vast majority of them are.
> >
> > So would it make sense to have "is_trivially_copyable_in_reality"
> > which will be 'true' for polymorphic types which are, in actual fact,
> > trivially copyable?
>
> By the way I do realise that the same class will be trivially copyable
> on some machines but not on others -- for example all polymorphic
> objects on Apple Silicon arm64e will not be trivially copyable
> (because the vtable pointer has to be re-signed or re-encrypted or
> whatever).


Putting a bit more thought into this. . .

Bitwise-copying a polymorphic object is fine so long as:
1) Its pointers are not encoded (e.g. pointer authentication on Apple
Silicon arm64e)
2) The class is final -- or we're guaranteed to be dealing with the
most-derived object
3) All copy constructors of base classes and sub-objects are 'default'

For some reason, the C++ Standard necessitates that a class have a
non-trivial destructor in order to be trivially copyable but I'm not
on board with that, so I'm removing that requirement. If a type can be
copied with a 'default' copy-constructor then there's nothing of
concern that the destructor can do. If you try to tell me that the
destructor deallocates memory or releases a resource, then I'll ask
you why the copy-constructor isn't allocating memory or acquiring a
resource. So the destructor argument doesn't wash with me -- I don't
think the destructor has anything at all to do with whether or not
it's okay to do a bitwise-copy of a polymorphic object.

The trait would look something like this:

template<typename T, bool guaranteed_complete_object = false>
constexpr bool is_trivially_copyable_in_reality =
       // If not a class, just use 'is_trivially_copyable'
       (!is_class_v<remove_all_extents_t<T>> && is_trivially_copyable_v<T>)

       ||

       (
           is_class_v<remove_all_extents_t<T>>
       && !has_any_non_default_copy_ctor<remove_all_extents_t<T>>

       // Prevent copying base object out of more-derived object
       && ( guaranteed_complete_object
           || is_final_v<remove_all_extents_t<T>>
           || ( !is_polymorphic_v<remove_all_extents_t<T>> &&
!has_any_virtual_bases<remove_all_extents_t<T>> ) )

       // Prevent bitwise-copying of encoded pointers on Apple Silicon arm64e
       && ( !is_vptr_encoded
           || ( !is_polymorphic_v<remove_all_extents_t<T>>
               && !has_any_virtual_bases<remove_all_extents_t<T>> ) )
       );

So then the implementation of std::vector could use memcpy whenever
copying a vector of elements which are, in reality, trivially
copyable.

By extension, all things where are trivially_copyable_in_reality are
also trivially relocatable.

Received on 2026-01-22 15:48:31