Search code examples
c++memory-managementio

Modern C++ idiom for allocating / deallocating an I/O buffer


For I/O work, I need to read N bytes into a buffer. N is known at run time (not compile time). The buffer size will never change. The buffer is passed to other routines to compress, encrypt, etc: it's just a sequence of bytes, nothing higher than that.

In C, I would allocate the buffer with malloc and then free it when I'm done. However, my code is modern C++, certainly no mallocs in place, and very few raw new and delete: I'm making heavy use of RAII and shared_ptr. None of those techniques seem appropriate for this buffer, however. It's just a fixed length buffer of bytes, to receive I/O and make its contents available.

Is there a modern C++ idiom to this elegantly? Or, for this aspect, should I just stick with good ol' malloc?


Solution

  • In C++14, there's a very syntactically clean way of achieving what you want:

    size_t n = /* size of buffer */;
    auto buf_ptr = std::make_unique<uint8_t[]>(n);
    auto nr = ::read(STDIN_FILENO, buf_ptr.get(), n);
    auto nw = ::write(STDOUT_FILENO, buf_ptr.get(), nr);
    // etc.
    // buffer is freed automatically when buf_ptr goes out of scope
    

    Note that the above construct will value-initialize (zero out) the buffer. If you want to skip the initialization to save a few cycles, you'll have to use the slightly uglier form given by lisyarus:

    std::unique_ptr<uint8_t[]> buf_ptr(new uint8_t[n]);
    

    C++20 introduces std::make_unique_for_overwrite, which allows the non-initializing line above to be written more concisely as:

    auto buf_ptr = std::make_unique_for_overwrite<uint8_t[]>(n);