Date: Fri, 23 Jan 2026 22:21:05 +0000
I need to try re-frame this all over again. And I'm realising now that
this was the missing step we needed toward settling on a final
solution for relocation. We will never figure out relocation in C++
until we figure out copying.
First of all I'll be specific about what I'm talking about. Consider
the following code that copies a vector:
vector< MyClass > vec1;
vec1.emplace_back( 1, 2, 3 );
vec1.emplace_back( 16, 2, 3567 );
vec1.emplace_back( 3234, 2, 333 );
auto vec2 = vec1;
The line immediately above copies an entire vector. This process will
involve two things:
A) allocating memory
B) copying objects
As an optimisation for B, I want to use 'memcpy' instead of running a
loop with 'construct_at'. But in order to be able to determine when I
can use this optimisation, I need a new trait. Right now the Standard
only has 'is_trivially_copyable' for this purpose but it needlessly
reports that all polymorphic objects cannot be memcpy'ed (even though
most of them can -- except for on arm64e). So we need a new trait.
As for the name of this new trait, well the word 'trivial' is no
longer usable in any context in C++ because of the extreme ambiguity
that has been given to it -- remember how we were gonna say an object
was 'trivially relocatable' even if you needed to run an encryption
algorithm after relocating it? And we called that encryption algorithm
"restart_lifetime"? So forget about the word 'trivial', it's useless
now.
Let's call this new trait: is_memcpyable
So the copy-constructor for vector would look something like the following:
template<typename T>
requires is_memcpyable<T>
vector::vector(vector const &rhs)
{
this->p = new char[ sizeof(T) * rhs.count ];
this->count = rhs.count;
memcpy( this->p, rhs.p, sizeof(T) * this->count );
}
But then the next question is whether the 'memcpy' operation should be
followed by something like "clone_lifetime"? And then maybe
"clone_lifetime" in similar vein to "restart_lifetime", should
re-encrypt the vptr? So then the copy-constructor would have one extra
line as follows:
template<typename T>
requires is_memcpyable<T>
vector::vector(vector const &rhs)
{
this->p = new char[ sizeof(T) * rhs.count ];
this->count = rhs.count;
memcpy( this->p, rhs.p, sizeof(T) * this->count );
for ( size_t i = 0u; i != this->count; ++i ) clone_lifetime(
rhs[i], (*this)[i] );
}
Since the 'clone_lifetime' function will only actually do something on
arm64e, it can be optimised away on every other architecture.
So the question we need to answer first is as follows:
The trait 'is_memcpyable' should mean either:
A) The type can be memcpy'ed and no further action required
or
B) The type can be memcpy'ed but then must be clone_lifetime'd
If we choose A, then all polymorphic objects on arm64e will report
false for is_memcpyable.
If we choose B, then some polymorphic objects on arm64e will report
true for is_memcpyable but you need to call clone_lifetime afterward
in order to resign the vptr and vbptrs.
We need to get this nailed down before we glance at relocation again.
What will it be? A or B?
this was the missing step we needed toward settling on a final
solution for relocation. We will never figure out relocation in C++
until we figure out copying.
First of all I'll be specific about what I'm talking about. Consider
the following code that copies a vector:
vector< MyClass > vec1;
vec1.emplace_back( 1, 2, 3 );
vec1.emplace_back( 16, 2, 3567 );
vec1.emplace_back( 3234, 2, 333 );
auto vec2 = vec1;
The line immediately above copies an entire vector. This process will
involve two things:
A) allocating memory
B) copying objects
As an optimisation for B, I want to use 'memcpy' instead of running a
loop with 'construct_at'. But in order to be able to determine when I
can use this optimisation, I need a new trait. Right now the Standard
only has 'is_trivially_copyable' for this purpose but it needlessly
reports that all polymorphic objects cannot be memcpy'ed (even though
most of them can -- except for on arm64e). So we need a new trait.
As for the name of this new trait, well the word 'trivial' is no
longer usable in any context in C++ because of the extreme ambiguity
that has been given to it -- remember how we were gonna say an object
was 'trivially relocatable' even if you needed to run an encryption
algorithm after relocating it? And we called that encryption algorithm
"restart_lifetime"? So forget about the word 'trivial', it's useless
now.
Let's call this new trait: is_memcpyable
So the copy-constructor for vector would look something like the following:
template<typename T>
requires is_memcpyable<T>
vector::vector(vector const &rhs)
{
this->p = new char[ sizeof(T) * rhs.count ];
this->count = rhs.count;
memcpy( this->p, rhs.p, sizeof(T) * this->count );
}
But then the next question is whether the 'memcpy' operation should be
followed by something like "clone_lifetime"? And then maybe
"clone_lifetime" in similar vein to "restart_lifetime", should
re-encrypt the vptr? So then the copy-constructor would have one extra
line as follows:
template<typename T>
requires is_memcpyable<T>
vector::vector(vector const &rhs)
{
this->p = new char[ sizeof(T) * rhs.count ];
this->count = rhs.count;
memcpy( this->p, rhs.p, sizeof(T) * this->count );
for ( size_t i = 0u; i != this->count; ++i ) clone_lifetime(
rhs[i], (*this)[i] );
}
Since the 'clone_lifetime' function will only actually do something on
arm64e, it can be optimised away on every other architecture.
So the question we need to answer first is as follows:
The trait 'is_memcpyable' should mean either:
A) The type can be memcpy'ed and no further action required
or
B) The type can be memcpy'ed but then must be clone_lifetime'd
If we choose A, then all polymorphic objects on arm64e will report
false for is_memcpyable.
If we choose B, then some polymorphic objects on arm64e will report
true for is_memcpyable but you need to call clone_lifetime afterward
in order to resign the vptr and vbptrs.
We need to get this nailed down before we glance at relocation again.
What will it be? A or B?
Received on 2026-01-23 22:20:11
