Nice:
using bytes = std::vector<std::byte>;
I would call it Bytes
to make it clear it is a type rather than an object.
This is not a good idea:
using namespace std;
See: Why is “using namespace std;” considered bad practice?
This is technically not valid C++.
byte data[length];
Variable sized arrays (VSA) are an extension to the language supported by several compilers but not actually part of the C++ standard. Though it is part of the more recent versions C standard.
Also creating a local array means that the data is being created on the local stack frame (here I am assuming a Von-Neumann like architecture). This means for the data to exist after the function completes means you will need to copy it out of the function. So an alternative data object is probably a good idea.
Also there is a limitation on the size of array allowed on the stack (there are hardware limitations on the size of stack frames on lots of architecture).
So a good idea would be to use the same data structure that you return.
Bytes data(length); // This is basically std::vector
Now in older versions of C++ there are some nice optimizations that can be applied to std::vector
when it is returned from a function that allow the compiler to build the std::vector
at the final destination so that it is not actually copied on return.
In modern versions of the compiler the language has the concept of move semantics built into the language. So returning a std::vector
is not an expensive operation as the internal buffer is moved (just the pointer is copied) from the function to the destination result.
Also the compiler is now required to perform copy elision of objects when it can.
Error checking
This code does zero error checking. There are several things that can go wrong and you don't check for any of them. But you said you removed this (you should have left it in).
So a better version:
#include <vector>
#include <string>
#include <fstream>
#include <cstdint>
using Bytes = std::vector<std::byte>;
Bytes read_block(std::uint32_t offset,
std::uint32_t length,
std::string const& filename)
{
// Not going to explicitly check these.
// The use of gcount() below will compensate for a failure here.
std::ifstream is(filename, std::ios::binary);
is.seekg(offset);
Bytes data(length);
is.read(reinterpret_cast<char*>(data.data()), length);
// We have to check that reading from the stream actually worked.
// If any of the stream operation above failed then `gcount()`
// will return zero indicating that zero data was read from the
// stream.
data.resize(is.gcount());
// Simply return the vector to allow move semantics take over.
return data;
}
byte data[length];
then creating a vector forces a copy. Why not makedata
a vector and simply return it. Then the compiler can do lots of optimization and build the vector directly at the destination so removing the need for a copy. \$\endgroup\$