C++17 will include std::byte
, a type for one atomically-addressable unit of memory, having 8 bits on typical computers.
Before this standardization, there is already a bit of dilemma when pointing into "raw" memory - between using char*
/unsigned char*
on one hand or void *
on the other. Now, one of reasons for prefering void *
is removed - std::byte
does not have the same connotations as a char
; it's about raw memory, not characters.
So, my question is: What is a good rule of thumb, for the days of std::byte
, regarding when to prefer it over void *
and when it's the other way around?
Of course when you're dealing with old code, or C code, you're constrained by what it accepts; I mostly mean new code where you get to choose all the types.
(This is a potential rule of thumb which comes off the top of my head, not condoned by anyone.)
Rule of thumb: When to use which kind of pointer?
char *
for sequences of textual characters, not anything else.void *
in type-erasure settings, i.e. when the pointed-to data is typed, but for some reason a typed pointer must not be used or it cannot be determined whether it's typed or not.byte *
for raw memory for which there is no indication of it holding any typed data.An exception to the above:
void *
/char *
when older or non-C++ forces you and you would otherwise usebyte *
- but wrap that with abyte *
-based interface as tightly as you can rather than exposing it to the rest of your C++ code.Examples
void * my_custom_malloc(size_t size)
- wrongbyte * my_custom_malloc(size_t size)
- rightstruct buffer_t { byte* data; size_t length; my_type_t data_type; }
- wrongstruct buffer_t { void* data; size_t length; my_type_t data_type; }
- rightWhat is the motivation for
std::byte
?Quoting from the original paper;
In essence,
std::byte
is there to "replace" the use ofchar
-types when required to deal with raw memory as bytes, it would be safe to assert that this is applicable when used by-value, by-refernce, pointers and in containers.Correct, so
std::byte
should be preferred overchar
-types when dealing with bytes in memory (as in, an array of bytes). Some lower level protocol data manipulation immediately comes to mind.I would argue that similar guides apply now as they did previously. When dealing with raw blocks of memory, where the byte addressability is required,
char *
etc. would have been preferred overvoid *
, I think the same logic applies now, but preferbyte *
overchar *
. Achar *
is better for a character sequences.If the desire is to pass around a pointer opaquely, the
void *
probably still best fits the problem.void *
essentially means "point to anything", but the anything is still something, we are just not saying what yet.Further, the types
uintptr_t
(andintptr_t
) would probably factor in as alternatives, depending of course on the desired application.New code generally has very limited use of
void *
outside of compatibility (where you don't get to choose the type). If you need byte based processing then favourbyte *
.First,
void *
still makes sense when you have to use a C library function or generally speaking to use any otherextern "C"
compatible function.Next a
std::byte
array still allows individual access to any of its elements. Said differently this is legal:It makes sense if you want to be able to allow that low level access, for example if you want to manually copy all or parts of the array.
On the other hand,
void *
is really an opaque pointer, in the sense that you will have to cast it (to achar
orbyte
) before being able to access its individual elements.So my opinion is that
std::byte
should be used as soon as you want to be able to address elements of an array or move a pointer, andvoid *
still makes sense to denote an opaque zone that will only be passed (hard to actually process avoid *
) as a whole.But real use case for
void *
should become more and more unusual in modern C++ at least at high level, because those opaque zones should normally be hidden in higher level classes coming with methods to process them. So IMHOvoid *
should in the end be limited to C (and older C++ versions) compatibiliy, and low level code (such as allocating code).std::byte
is not just about "raw memory", it is byte-addressable raw memory with bitwise operations defined for it.You should not use
std::byte
to just blindly replacevoid*
.void*
retains its use.void*
means to the handling code "this is a block of data but I don't know what this data is, nor do I know how to operate on it.Use
std::byte
when you need byte address of the memory block and only bitwise operations defined for operating on that data.std::byte
does not have regular basic math operations defined, such asoperator+
,operator-
oroperator*
. That's right, the following code is illegal:In other words, use
void*
when it is not the handling codes business the contents.std::byte Example
Like I said above, all you can do on a
std::byte
are the bitwise operations like|
,&
and~
. An example of the use ofstd::byte
follows, note you need a C++17 compiler to compile this example, there is one here but you must select C++17 from the dropdown at the top right