Как использовать istream со строками

Я хотел бы прочитать файл в строке. Я ищу различные способы, как сделать это эффективно.

Использование фиксированного размера * char buffer

Я получил ответ от Тони, что создает буфер 16 КБ и читает в этот буфер, и добавляет буфер, пока нет ничего более читаемого. Я понимаю, как это работает, и я нашел это очень быстро. Я не понимаю, что в комментариях этого ответа говорится, что таким образом копирует все дважды. Но, как я понимаю, это происходит только в памяти, а не с диска, поэтому это почти незаметно. Это проблема в том, что он копирует из буфера в строку в памяти?

Использование istreambuf_iterator

В другом ответе, который я получил, используется istreambuf_iterator. Код выглядит красивым и минимальным, но он очень медленный. Я не знаю, почему это происходит. Почему эти iteratorы так медленно?

Использование memcpy ()

По этому вопросу я получил комментарии, что я должен использовать memcpy (), поскольку это самый быстрый метод native. Но как я могу использовать memcpy () со строкой и объектом ifstream? Предполагается, что если stream не работает со своей функцией чтения? Почему использование memcpy () разрушает переносимость? Я ищу решение, совместимое с VS2010, а также с GCC. Почему memcpy () не будет работать с ними?

+ Любой другой эффективный способ?

Что вы рекомендуете, какую оболочку я использую, для небольших <10 МБ двоичных файлов?

(Я не хотел разделять этот вопрос по частям, так как меня больше интересует сравнение между другим способом, как я могу прочитать ifstream в строке)

это происходит только в памяти, а не с диска, поэтому почти незаметно

Это действительно правильно. Тем не менее, решение, которое этого не делает, может быть быстрее.

Почему эти iteratorы так медленно?

Код медленный не из-за iteratorов, а потому, что строка не знает, сколько памяти выделяется: istreambuf_iterator s может быть пройден только один раз, поэтому строка по существу вынуждена выполнять повторяющиеся конкатенации с istreambuf_iterator выделениями памяти, которые очень медленны ,

Мой любимый однострочный шрифт, из другого ответа , передается непосредственно из базового буфера:

 string str(static_cast(stringstream() << in.rdbuf()).str()); 

На недавних платформах это действительно предопределит буфер. Однако он все равно приведет к избыточной копии (от stringstream до конечной строки).

Наиболее общим способом, вероятно, будет ответ с использованием istreambuf_iterator :

 std::string s( (std::istreambuf_iterator( source )), (std::istreambuf_iterator()) ); 

Хотя точная производительность очень зависит от реализации, маловероятно, что это самое быстрое решение.

Интересной альтернативой было бы:

 std::istringstream tmp; tmp << source.rdbuf(); std::string s( tmp.str() ); 

Это может быть очень быстрым, если реализация хорошо справляется с operator<< который вы используете, и тем, как он istringstream строку внутри istringstream . Однако некоторые более ранние реализации (и, возможно, еще более недавние) были очень плохими.

В целом производительность с использованием std::string будет зависеть от того, насколько эффективна реализация при выращивании строки; реализация не может определить, насколько велико, чтобы сделать это изначально. Вы можете сравнить первый алгоритм с использованием того же кода с std::vector вместо std::string , или если вы можете сделать хорошую оценку максимального размера, используя reserve или что-то вроде:

 std::string s( expectedSize, '\0' ); std::copy( std::istreambuf_iterator( source ), std::istreambuf_iterator(), s.begin() ); 

memcpy не может читать из файла и с хорошим компилятором, будет не так быстро, как использование std::copy (с теми же типами данных).

Я склонен использовать второе решение выше, с << на rdbuf() , но это частично по историческим причинам; Я привык к этому (используя istrstream ), прежде чем STL будет добавлен в стандартную библиотеку. В этом случае вы можете поэкспериментировать с istrstream и предварительно выделенным буфером (предположим, что вы можете найти соответствующий размер для буфера).