Date: Thu, 24 Apr 2025 16:36:29 +0100
On Thu, Apr 24, 2025 at 2:09 AM Elazar wrote:
>
> BigExpensiveType obj = moved_from<BigExpensiveType>();
> obj = get_actual_value(); // Now we're just overwriting a moved-from state
Or alternatively, use an "std::optional<BigExpensiveType>".
The template class "std::optional" needs an extra byte (or at least an
extra bit somehow) to indicate whether it currently houses a valid
object.
When writing the implementation of the template class "std::optional",
the need for an extra byte/bit can be overcome in two ways:
(1) Smart use of the "__datasizeof" operator in contrast to the
"sizeof" operator
(2) Use of the attribute [[no_unique_address]]
But there's a third possibility: If tagging were to become a part of
the Standard, then the class 'BigExpensiveType' could have the tag
"all_bits_zero_invalid". This tag tells you that if all the bits are
zero for an object of 'BigExpensiveType', then it's not a valid
object. Then the 'operator=' can be written something like:
template<typename T>
void std::optional<T>::reset(void) noexcept
{
if ( (0 != buf[0]) || std::memcmp(buf, buf + 1, size - 1) )
{
// There is a valid object housed, so call
// its destructor in here
}
}
Alternatively you can write manage your own buffer:
alignas(T) char unsigned buf[ __datasizeof(T) ];
T &myobj = *(T*)&buf;
Or maybe write your own class similar to "std::optional" but for the
sake of optimisation, assume that programmer will use it properly and
so remove all safety checks (e.g. in the destructor, destroy the
housed object without confirmation that it was ever created).
>
> BigExpensiveType obj = moved_from<BigExpensiveType>();
> obj = get_actual_value(); // Now we're just overwriting a moved-from state
Or alternatively, use an "std::optional<BigExpensiveType>".
The template class "std::optional" needs an extra byte (or at least an
extra bit somehow) to indicate whether it currently houses a valid
object.
When writing the implementation of the template class "std::optional",
the need for an extra byte/bit can be overcome in two ways:
(1) Smart use of the "__datasizeof" operator in contrast to the
"sizeof" operator
(2) Use of the attribute [[no_unique_address]]
But there's a third possibility: If tagging were to become a part of
the Standard, then the class 'BigExpensiveType' could have the tag
"all_bits_zero_invalid". This tag tells you that if all the bits are
zero for an object of 'BigExpensiveType', then it's not a valid
object. Then the 'operator=' can be written something like:
template<typename T>
void std::optional<T>::reset(void) noexcept
{
if ( (0 != buf[0]) || std::memcmp(buf, buf + 1, size - 1) )
{
// There is a valid object housed, so call
// its destructor in here
}
}
Alternatively you can write manage your own buffer:
alignas(T) char unsigned buf[ __datasizeof(T) ];
T &myobj = *(T*)&buf;
Or maybe write your own class similar to "std::optional" but for the
sake of optimisation, assume that programmer will use it properly and
so remove all safety checks (e.g. in the destructor, destroy the
housed object without confirmation that it was ever created).
Received on 2025-04-24 15:36:41