Прочитать файл, используя C++ и RAII
Какой лучший способ прочитать файл с использованием C++ и RAII? Все примеры, которые я видел, используют что-то похожее на код ниже:
#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;
}
}
Согласно тому, что я знаю о RAII, кажется неправильным инициализировать указатель на символ и удалить его вручную.
Я сделал что-то похожее на:
#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);
}
}
Но я тоже не уверен, правильно ли это. Я также не смог успешно разыграть std::shared_ptr<char>
к std::shared_ptr<uint8_t>
если нужно (или если это возможно, или если это вообще имеет смысл?).
2 ответа
символ * буфер = новый символ [длина]; // Кажется неправильным?
Это не так, просто... небезопасно.
Более безопасные реализации:
std::unique_ptr<char[]> buffer{new char [length]}; // note: use char[] as parameter
is.read (buffer.get(), length);
Лучше, чем предыдущий:
std::vector<char> buffer{length, ' '};
is.read (buffer.data(), length);
или же:
std::string buffer{length, ' '};
is.read (buffer.data(), length);
В частности, это UB:
std::shared_ptr<char> buffer = std::make_shared<char>();
is.read (buffer, length);
потому что он выделяет один символ динамически, а затем помещает до длинных символов в этом месте памяти. На практике это переполнение буфера, если только ваша длина не равна 1.
std::shared_ptr (как и другие умные указатели) применяет RAII к одному экземпляру объекта (здесь один символ, упс!)
Вы ищете std::vector, который вы можете предварительно выделить, вызвав vec.reserve().
Что касается приведения его к uint8_t, я бы сказал, что вызов vec.data() после того, как вы прочитали свои данные и приведение результата к uint8_t, должен работать как положено (хотя я не буду утверждать, что это стандартно).