A C API often receives a pointer and a byte count. Neither tells it how much storage is actually available. Your adapter must establish that fact before the call. In C++ the familiar
Choose the operation by its preconditions
memcpy copies a known nonoverlapping range. memmove supports overlap. Neither scans for a terminator or checks capacity. In a right shift, writing the first destination byte can overwrite the next source byte; a handwritten forward loop is therefore not a general replacement for memmove. Left shifts that happen to work do not prove that loop correct.
A memory-function count is in bytes. For an array of records, count times sizeof(record) must fit size_t before allocating or transferring. Inside one existing span, validate the starting positions first and compare the requested count with size minus each position. Computing the endpoint by addition can wrap and incorrectly approve an enormous request.
Follow one complete example
Run this program, then change one boundary while keeping the API preconditions valid. Predict its output before pressing Run.
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
int main() {
std::array<unsigned char,6> bytes{10,20,30,40,50,60};
std::memmove(bytes.data()+2,bytes.data(),4);
for(auto b:bytes) std::printf("%u ",unsigned(b));
std::puts("");
}Bytes are not automatically values
memcmp compares object representations and only promises the sign of its result. Padding bytes, multiple representations and field interpretation make it unsuitable as a general struct equality operator. A zero fill is a byte operation too: do not use memset as a constructor for std::string, a virtual object or a resource-owning class.
For a trivially copyable type there are specific representation-copy guarantees. They do not permit bypassing every lifetime, alignment or aliasing rule. This exercise stays entirely within already-existing std::byte elements so the operation has a clear, bounded meaning. Use typed algorithms, assignment or bit_cast where their stronger types express the actual operation.
Make the empty case explicit
An empty span may have a null data pointer. A wrapper can return success for its valid zero-length case without passing that pointer to a C function or computing pointer arithmetic on it. Positions beyond the end are still invalid even if the count is zero.
State the failure guarantee before implementing the copy: a rejected range changes nothing. Test invalid requests against a saved snapshot as well as checking the returned bool. For overlap, derive the expected result from a separate source snapshot so the test does not repeat the same copy algorithm.
Read the return value
Predict this smaller case. The check item later changes the values, so explain the rule as well as the output.
#include <cstdio>
#include <cstring>
int main() { char b[]="ABCDE"; std::memmove(b+1,b,4); std::puts(b); }Complete the faded example
State the missing precondition or result check before filling the code. The fill exercise supplies the rest of the implementation.
if (source > storage.size() || destination > storage.size()) return false;
// Fill: validate count without forming an overflowing endpoint.
// Fill: implement a valid zero-length no-op and an overlapping move.Check your model
A move with source == destination and a valid nonzero count should succeed. Which validation rule makes that work without a special copy loop?
Practice the boundary
Implement bool move_bytes(std::span<std::byte> storage, std::size_t destination, std::size_t source, std::size_t count).
Move exactly count bytes within one borrowed buffer, as if copied through temporary storage. Both overlapping directions and identical ranges must work. Use the C memory-function interface.
Accept positions at the end only when the requested count is zero. Reject any position beyond the end or any range that does not fit; return false without changing any bytes. Avoid overflow in range arithmetic. A valid zero-length operation, including an empty span, succeeds without dereferencing pointers. Return true on success. No allocation or ownership transfer is needed.
Read → six checks → two bug hunts → fill → build. A successful graded submission is evidence; reading or watching alone does not grant mastery. Review cards reinforce API choices separately.
Watch and verify
The Watch & read panel links a free lecture for the relevant background and primary API references. The lecture notes say which parts are background; the tested contract here supplies the exact wrapper policy.
C standard-library course · C library review cards · Unix/Linux systems