Date: Sun, 21 Jul 2024 17:52:48 +0000
Why?
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]>
Sent: Sunday, July 21, 2024 6:51:17 PM
To: std-proposals <std-proposals_at_[hidden]>
Cc: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Subject: [std-proposals] all bytes zero == null object
Typically when implementing a class such as 'std::optional', the size
of 'std::optional<T>' is equal to "sizeof(T) + 1u", because one more
byte is needed to store a boolean to indicate whether there is a valid
object in existence.
We can use "__datasizeof" or "[[no_unique_address]]" in order to try
use the tail padding of T to store the boolean, and if we succeed,
then sizeof(optional<T>) == sizeof(T).
If T has no tail padding, then we need an extra byte to store the
boolean. Unless . . . we had the ability to mark the class
'null_bytes==null_object" as follows:
class T (null_bytes==null_object) {
. . .
};
Marking a class as 'null_bytes==null_object' means that a byte-pattern
of all zeroes is a 'null object'. The standard header <type_traits>
would then have "std::is_null_bytes_null_object".
So then "std::optional::has_value" could be:
bool optional::has_value(void) noexcept requires
is_null_bytes_null_object_v<T>
{
return (0u == *storage) && !memcmp(storage, storage + 1u,
sizeof(storage) - 1u);
}
Another effect of marking a class as 'null_bytes==null_object' would
be that the destructor doesn't get called. For instance the following
program won't crash:
struct T (null==0) {
int a, b, c;
~T(void) { *(int*)nullptr = 666; }
};
int main(void)
{
T var = {0,0,0};
}
The above program doesn't have undefined behaviour, because the
destructor is treated as though it were written:
~T(void)
{
char const *const p = (char*)this;
if ( (0u == *p) && !memcmp(p, p + 1u, sizeof(*this) - 1u) ) return;
*(int*)nullptr = 0;
}
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]>
Sent: Sunday, July 21, 2024 6:51:17 PM
To: std-proposals <std-proposals_at_[hidden]>
Cc: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Subject: [std-proposals] all bytes zero == null object
Typically when implementing a class such as 'std::optional', the size
of 'std::optional<T>' is equal to "sizeof(T) + 1u", because one more
byte is needed to store a boolean to indicate whether there is a valid
object in existence.
We can use "__datasizeof" or "[[no_unique_address]]" in order to try
use the tail padding of T to store the boolean, and if we succeed,
then sizeof(optional<T>) == sizeof(T).
If T has no tail padding, then we need an extra byte to store the
boolean. Unless . . . we had the ability to mark the class
'null_bytes==null_object" as follows:
class T (null_bytes==null_object) {
. . .
};
Marking a class as 'null_bytes==null_object' means that a byte-pattern
of all zeroes is a 'null object'. The standard header <type_traits>
would then have "std::is_null_bytes_null_object".
So then "std::optional::has_value" could be:
bool optional::has_value(void) noexcept requires
is_null_bytes_null_object_v<T>
{
return (0u == *storage) && !memcmp(storage, storage + 1u,
sizeof(storage) - 1u);
}
Another effect of marking a class as 'null_bytes==null_object' would
be that the destructor doesn't get called. For instance the following
program won't crash:
struct T (null==0) {
int a, b, c;
~T(void) { *(int*)nullptr = 666; }
};
int main(void)
{
T var = {0,0,0};
}
The above program doesn't have undefined behaviour, because the
destructor is treated as though it were written:
~T(void)
{
char const *const p = (char*)this;
if ( (0u == *p) && !memcmp(p, p + 1u, sizeof(*this) - 1u) ) return;
*(int*)nullptr = 0;
}
-- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2024-07-21 17:52:52