C ++ ifstream :: read () и массивы C - PullRequest
4 голосов
/ 09 июля 2011

Похоже, что существует общее мнение о том, что массивы C плохие и что использование более разумных альтернатив, таких как векторы или строки C ++, - путь. Здесь нет проблем.

Сказав это, почему read() член ifstream вводит данные в char* ... Вопрос в том, могу ли я каким-то образом ввести вектор байтов, используя только STL?

Связанный бонусный вопрос: часто ли вы проверяете ios::badbit и ios::failbit, особенно если вы работаете с динамически размещаемой строкой C в этой области? Делаете ли вы освобождение строки C в catch()?

Спасибо за чтение.

Ответы [ 2 ]

2 голосов
/ 09 июля 2011

Сказав это, почему read () является членом входных данных ifstream для char * ...

Это был проектный выбор.Не обязательно самый умный.

Вопрос в том, могу ли я каким-либо образом вводить в вектор байтов

Базовое хранилище для std::vector<char> гарантированно будет смежных (т. Е. Один блок памяти), так что да.Чтобы использовать ifstream::read, вы должны (a) убедиться, что размер вектора достаточно велик (используя .resize() - , а не .reserve()! Это потому, что вектор не может знать о данных, которые вывы читаете его неиспользованный capacity и обновляете его size), а затем (b) получаете указатель на начальный элемент вектора (например, с &v.front() или &(v[0])).

Если вы не хотите предварительно изменять размер вектора, вы можете использовать более продвинутые методы, которые включают типы итераторов и стандартные библиотечные алгоритмы.Это дает преимущество в том, что вы можете легко прочитать весь файл в векторе, не проверяя сначала длину файла (а стандартные приемы для проверки длины файла могут быть не такими надежными, как вы думаете!).

Это выглядит примерно так:

#include <iterator>
#include <algorithm> // in addition to what you already have.
// ...
std::ifstream ifs;
std::vector v;
// ...
std::istreambuf_iterator<char> begin(ifs), end;
std::copy(begin, end, std::back_inserter(v));

Вектор байтов, конечно, не строка .Но вы можете сделать то же самое с std::string - функция std::back_inserter достаточно умна, чтобы создать соответствующий тип итератора для любого предоставленного типа, который обеспечивает .push_back(), что и string, и vector.Это магия шаблонов.:)

используя только STL?

Я в замешательстве.Я думал, что мы говорим о стандартной библиотеке C ++.Что это за STL, о котором вы говорите?

Соответствующий бонусный вопрос: часто ли вы проверяете ios :: badbit и ios :: failbit

Нет;Я обычно пишу код таким образом, что я могу просто проверить результат операции чтения напрямую.См. http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4 для примера / обсуждения.

особенно если вы работаете с динамически размещаемой строкой C в этой области?

Это плохая идеяв общем.

Делаете ли вы освобождение строки C в catch ()?

И иметь дело с такого рода вещами является одним изОсновные причины, почему.Это не легко, чтобы получить право.Но я надеюсь, вы понимаете, что перехват исключения и проверка ios :: bits - это две совершенно разные вещи.Хотя вы можете сконфигурировать объект потока для выдачи исключений, а не просто устанавливать биты флага:)

2 голосов
/ 09 июля 2011

Вы можете читать непосредственно в выделенный вектор (у меня нет возможности компилировать это отсюда, поэтому могут быть опечатки или транспонированные параметры и т. Д.), Но идея верна.

vector<char> data;
data.resize(100);

// Read 100 characters into the storage of data
thing.read(&data[0], 100);
...