Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What should a void*/std::size_t function argument pair be changed to for an interface that writes binary files?

Tags:

c++

The C++ core guidelines state many times that using void* as an argument is at best confusing and at worst error-prone. My favorite mention is at the end:

C++ Core Guidelines: To-do: Unclassified proto-rules

Anyone writing a public interface which takes or returns void* should have their toes set on fire. That one has been a personal favorite of mine for a number of years. :)

That said:

What should this function signature be changed to in order to comply with this suggestion? Currently it works with anything, that can be reinterpreted as a const char*:

bool writeBufferToFile(void* buffer, std::size_t size, const std::string& filePath) const
{
    namespace FS = std::filesystem;
    FS::path p(filePath);
    p.make_preferred();
    bool not_valid_path = FS::is_directory(p);
    bool invalid = not_valid_path;
    if(invalid) { return false; }

    std::ofstream ofs;
    ofs.open(p.string(), std::ios_base::binary);
    if(ofs)
    {
        ofs.write(reinterpret_cast<const char*>(buffer), size);
        return true;
    }
    return false;
}
like image 904
Casey Avatar asked Dec 09 '25 21:12

Casey


1 Answers

What you want is not two parameters, a pointer and a size, but one parameter that represents a binary chunk of data. In an ideal world, you might use something like std::vector<std::uint8_t> const&, but the problem with this is that it forces callers to do an allocate/copy/free if they happen to store the data some other way.

So what you really want is a class that represents a binary chunk of data but doesn't own that data and can be constructed, copied, and destroyed very cheaply regardless of how the underlying data is stored. This avoids the need to have two parameters to express one concept.

A class that encapsulates this is often called a Slice. So I would suggest:

class Slice
{
private:
    std::uint8_t const* data_;
    std::size_t size_;
  ...
};

bool writeBufferToFile (const Slice& data, const std::string& filePath) const

Your Slice class can easily be constructed from a std::vector <std::uint8_t> or pretty much any other sensible way of holding a range of bytes.

like image 55
David Schwartz Avatar answered Dec 12 '25 10:12

David Schwartz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!