To copy from a C++20 std::span
into an std::vector
I can simply do the following:
void WriteBuffer(std::vector<std::byte>& destData, const std::span<const std::byte>& srcData)
{
std::copy(srcData.begin(), srcData.end(), destData.end());
}
..which will be optimised to a single memmove
. See example: https://godbolt.org/z/8nPjzj3c6
However, if I replace std::span
with gsl::span
we don't get this optimisation anymore: https://godbolt.org/z/MWfPKW8eq
Is it best to instead resize the vector and use std::memcpy
to copy over the data, or are there better alternatives?
My understanding is that gsl::span
does not get optimised, because it's using a custom iterator that the implementation of std::copy
is not aware of - so it cannot make assumptions about the linearity of the data - is that right? If so, I suppose all STL containers and algorithms will have the same issue with gsl::span
and any other data structures that use custom iterators. But please let me know if I've misunderstood something.
Update: Sorry, there was a mistake here. As @Caleth kindly pointed out, I'm writing out of bounds. However, resizing first and then using copying to destData.begin()
(yes overwriting, just for simplicity..) doesn't really change it - it still copies byte-by-byte.
because it's using a custom iterator that the implementation of std::copy is not aware of
Not really. The standard library would see this member and have the same knowledge about the data layout.
#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
using iterator_concept = std::contiguous_iterator_tag;
#endif // __cpp_lib_ranges
The more likely reason is that the iterator operations are checked at runtime, rather than the "undefined behaviour when misused" of std::span
.
If you were to read out of range of srcData
, using std::span
the behaviour is undefined. Using gsl::span
, the behaviour is defined, std::terminate
is called. The "missing optimisations" are probably because memcpy
ing out of range data is not the same as calling std::terminate
Your example code exhibits undefined behaviour when srcData
has any elements, because you can't write past the end of a vector.