Date: Tue, 23 Jul 2024 09:56:28 +0100
On Mon, Jul 22, 2024 at 4:58 PM Ville Voutilainen wrote:
>
> Indeed. Furthermore, for example, you can have code that processes the
> optional, checks that it's engaged,
> and then hands the result of *opt to some other code for filling in
> the value, perhaps by simple assignment. If you don't know the
> difference between a disengaged optional and an optional holding a
> 'null' value, then you can no longer
> do that.
>
> And there's of course the rather canonical database field example,
> where there is a difference between a field
> not being set at all, and a field being set to a null string. Or null
> whatever, but nevertheless set to some value, possibly null.
This isn't what I meant. Let me give the example of a class that
tracks at any one time 2 - 4 unique semaphores:
class Tracker {
typedef std::counting_semaphore<3> Sem;
std::atomic<Sem*> sems[4u];
public:
Tracker(Sem *const s0,Sem *const s1,Sem *const s2 =
nullptr,Sem *const s3 = nullptr)
{
if ( nullptr != s0 ) { assert( s0 != s1 ); assert( s0
!= s2 ); assert( s0 != s3 ); }
if ( nullptr != s1 ) { assert( s1 != s0 ); assert( s1
!= s2 ); assert( s1 != s3 ); }
if ( nullptr != s2 ) { assert( s2 != s1 ); assert( s2
!= s0 ); assert( s2 != s3 ); }
sems[0] = s0;
sems[1] = s1;
sems[2] = s2;
sems[3] = s3;
}
// other methods go here for manipulating the semaphores
};
Given that an object of the type 'Tracker' must always track at least
2 semaphores, we know that at least 2 of its 4 pointers won't be a
nullptr. Furthermore, even if we were working with a machine for which
all bits zero is a valid memory addresss (and therefore nullptr must
be something other than all bits zero), the second pointer must be
unequal to the first pointer, so there must be one bit set high
somewhere.
An object of type 'Tracker' that has all bytes zero simply cannot
exist -- it is not a valid object. Never will there be such an object.
Perhaps my terminology of a 'null object' wasn't a good choice.
Therefore, an implementation of "std::optional<Tracker>", in
implementing the 'reset' method, can call "~Tracker()" and then simply
do a 'memset all zero' on the storage space. After that, the
'has_value' method can just check if all bytes are zero.
>
> Indeed. Furthermore, for example, you can have code that processes the
> optional, checks that it's engaged,
> and then hands the result of *opt to some other code for filling in
> the value, perhaps by simple assignment. If you don't know the
> difference between a disengaged optional and an optional holding a
> 'null' value, then you can no longer
> do that.
>
> And there's of course the rather canonical database field example,
> where there is a difference between a field
> not being set at all, and a field being set to a null string. Or null
> whatever, but nevertheless set to some value, possibly null.
This isn't what I meant. Let me give the example of a class that
tracks at any one time 2 - 4 unique semaphores:
class Tracker {
typedef std::counting_semaphore<3> Sem;
std::atomic<Sem*> sems[4u];
public:
Tracker(Sem *const s0,Sem *const s1,Sem *const s2 =
nullptr,Sem *const s3 = nullptr)
{
if ( nullptr != s0 ) { assert( s0 != s1 ); assert( s0
!= s2 ); assert( s0 != s3 ); }
if ( nullptr != s1 ) { assert( s1 != s0 ); assert( s1
!= s2 ); assert( s1 != s3 ); }
if ( nullptr != s2 ) { assert( s2 != s1 ); assert( s2
!= s0 ); assert( s2 != s3 ); }
sems[0] = s0;
sems[1] = s1;
sems[2] = s2;
sems[3] = s3;
}
// other methods go here for manipulating the semaphores
};
Given that an object of the type 'Tracker' must always track at least
2 semaphores, we know that at least 2 of its 4 pointers won't be a
nullptr. Furthermore, even if we were working with a machine for which
all bits zero is a valid memory addresss (and therefore nullptr must
be something other than all bits zero), the second pointer must be
unequal to the first pointer, so there must be one bit set high
somewhere.
An object of type 'Tracker' that has all bytes zero simply cannot
exist -- it is not a valid object. Never will there be such an object.
Perhaps my terminology of a 'null object' wasn't a good choice.
Therefore, an implementation of "std::optional<Tracker>", in
implementing the 'reset' method, can call "~Tracker()" and then simply
do a 'memset all zero' on the storage space. After that, the
'has_value' method can just check if all bytes are zero.
Received on 2024-07-23 08:56:41