Suppose I have
int foo(void* p, size_t size_in_bytes);
and assume it doesn't make sense to make foo
typed. I want to be a good coder and apply the C++ core guidelines. Specifically, I want to use spans instead of (*, len) pairs. Well, span<void>
won't compile (can't add to a void *
); and span<char>
or span<uint8_t>
etc. would imply foo actually expects chars, which it might not.
So should I use a span<something-with-size-1>
in this case, or stick with void*
?
There can be no general answer to this question.
For a function to say that it takes a span<T>
means that it takes a contiguous array of values, without any form of ownership transference. If that description does not reasonably represent what is going on, then it should not take a span<T>
.
For example:
What if the function checks whether the buffer intersects a region in my memory space which is, say, mapped to a file?
That doesn't sound like a span<T>
. That sounds like you should have a simple aggregate with a name that makes it clear what it means:
struct memory_region
{
void* p;
size_t size_in_bytes;
};
You could even give it a member function for testing intersections. If you are making a system for dealing with such regions of memory, I might advise a more encapsulated class type with constructors and such.
What type the function takes should explain what the data means. Preferably this meaning would be in a general sense, but at the very least, it should say what it means for the function in question.
One more thing:
or
span<uint8_t>
etc. would imply foo actually expects chars
No, it would not. While uint8_t
will almost certainly have the same size as an unsigned char
, that does not mean that one would expect to be able to pass an array of characters to any function which takes span<uint8_t>
. If that function wanted to advertise that it accepted characters, it would have used unsigned char
.
I meant to say
span<whatever>
would imply the function expectwhatever
's.
Yes, the requirement for span
s is that it is passed an actual array of T
s of the given size.
The proposal before the C++ standardization committee is that if you want to pass around a pointer to a sequence of bytes (which is often what people want to do when passing void*
around), then you would pass a span<std::byte>
, which relies upon a new std::byte
type. However, that requires a small change to the language standard to be legal.
In today's C++, you could pass span<unsigned char>
(typedef'd as you find most descriptive) and get the same effect: access to a sequence of bytes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With