Search code examples
c++raii

Read a file using C++ and RAII


What's the best way to read a file in using C++ and RAII? All the examples I've seen use something similar to the code below:

#include <iostream>
#include <fstream>

int main () {

  std::ifstream is ("test.txt", std::ifstream::binary);
  if (is) {
    is.seekg (0, is.end);
    int length = is.tellg();
    is.seekg (0, is.beg);

    char * buffer = new char [length]; // Seems wrong?

    is.read (buffer, length);

    delete[] buffer;
  }
}

According to what I know of RAII it seems wrong to initialize a char pointer and manually remove it.

I've done something similar to:

#include <iostream>
#include <fstream>

int main () {

  std::ifstream is ("test.txt", std::ifstream::binary);
  if (is) {
    is.seekg (0, is.end);
    int length = is.tellg();
    is.seekg (0, is.beg);

    std::shared_ptr<char> buffer = std::make_shared<char>();

    is.read (buffer.get(), length);
  }
}

But I'm not sure if that's right either. I've also not been able to successfully cast std::shared_ptr<char> to a std::shared_ptr<uint8_t> if needed (or if it's possible, or if it even makes sense?).


Solution

  • char * buffer = new char [length]; // Seems wrong?

    It's not wrong, just ... unsafe.

    Safer implementations:

    std::unique_ptr<char[]> buffer{new char [length]}; // note: use char[] as parameter
    is.read (buffer.get(), length);
    

    Better than previous:

    std::vector<char> buffer{length, ' '};
    is.read (buffer.data(), length);
    

    or:

    std::string buffer{length, ' '};
    is.read (buffer.data(), length);
    

    In particular, this is undefined behavior:

    std::shared_ptr<char> buffer = std::make_shared<char>();
    is.read (buffer, length);
    

    because it allocates one character dynamically, then places up to length characters at that memory location. In practice, this is a buffer overflow, unless your length is always 1.