Самый безопасный способ извлечь из потока в массив символов или std :: string - PullRequest
1 голос
/ 16 декабря 2010

Я обеспокоен переполнением буфера, и мне нужно извлечь некоторые символы из класса, производного от std :: istream.Из того, что я понимаю, нет способа передать поток в std :: string непосредственно из istream, без моего собственного >> оператора.Поэтому я подумал о том, чтобы передать содержимое в массив char, а затем поместить его в std :: string.Вот простой пример:

char CharArray[1000] = {0};
SomeIStream >> CharArray;
std::string StuffFromStream(CharArray);

Однако, похоже, нет никакого способа узнать, что CharArray не будет переполнен.Есть ли какой-то максимум, который оператор извлечения потока будет записывать в chararray?Есть ли способ проверить, сколько будет извлечено превентивно?Это просто неправильно? Есть ли способ, который намного лучше, чем этот?

Edit1: я исправил не утечку памяти.Нет необходимости звонить удалить.Я не могу поверить, что я это сделал.

Edit2: было предложено использовать >> непосредственно в строку.Я пытался, что предыдущая в кодовой базе эта проблема возникла, и она не удалась.Сказать, что не найдено подходящего соответствия для оператора.Затем я попытался с std :: fstream, и это снова не удалось.Попытка кода std :: fstream в простом минималистичном проекте увенчалась успехом.Это говорит мне о том, что с моим большим проектом что-то не так.Первоначальная цель этого вопроса больше не действительна.

Edit3: я решил это.Я попытался выполнить потоковую передачу на строку typedef String, которая, на мой взгляд, была и std :: string, но на самом деле это была const std :: String.Естественно, нет оператора извлечения потока для записи в недоступный для записи объект, поэтому он просто дал мне все операторы, перечисленные в заголовке istream (тот, который мне нужен был в заголовке строки).

Благодарялюди, которые указали на мое ошибочное исследование и указали мне правильное направление.

Ответы [ 5 ]

3 голосов
/ 16 декабря 2010

Если вы (правильно) унаследованы от std :: istream, то вам не нужно делать ничего особенного, и вы можете просто использовать operator >> (std::istream&, std::string&).

std::string s;
SomeIStream >> s;

Когда я говорю «правильно», я имею в виду переопределение соответствующих виртуальных функций из istream.

«Я знаю, что если перед удалением будет исключение, это приведет к утечке памяти».Нет, не будет.Вы не выделили CharArray с new;вызов delete не будет делать то, что вы хотите.

0 голосов
/ 16 декабря 2010

Таков мой подход (из книги «Мышление на С ++» Брюса Экеля) ::

ifstream in("somefile.txt",ios::in);
istreambuf_iterator istr(in),end;
string str;
insert_iterator ins(str,str.begin());

while(istr != end){
      *ins++ = *istr++;
}

В приведенном выше коде весь файл берется как символьный поток, а затем помещается в строку. Это показано только в качестве примера.

0 голосов
/ 16 декабря 2010

Если вы хотите прочитать весь поток в строку, это не очень эффективно, но безопасно:

std::string str((std::istream_iterator<char>(some_istream)), std::istream_iterator<char>());

(обратите внимание на дополнительные скобки, чтобы избежать самого неприятного анализа)

Если вы хотите прочитать до «n» символов:

some_istream.read(some_char_array, sizeof(some_char_array));

обратите внимание, что это не приведет к нулевому завершению массива.Вместо этого передайте sizeof(char_array) - 1, если хотите оставить последний символ массива без изменений.

0 голосов
/ 16 декабря 2010

Все потоки предлагают метод .str (), который предоставит копию своего буфера в виде std :: string (или wstring или чего-либо еще для других typedefs).

Кроме того, вы объявили массив в стеке, а затем попытались удалить его, то есть UB.

0 голосов
/ 16 декабря 2010

Смешивание массивов символов старой школы в стиле C с потоками?Похоже, какой-то очень запутанный код.

Оставьте комментарий, просто извлеките непосредственно в строку.Вы можете передать это (с помощью метода c_str()) API-интерфейсам в стиле C, которые ожидают параметры const char*.И если по какой-то странной причине вы действительно нуждаетесь в массиве char, вы можете copy из string в массив char безопасно, после проверки границ.

Кстати, вы довольно четко проиллюстрировалиосновной способ, которым магические числа являются злом .В вашем случае рассматриваемое магическое число - 1000.Вы не представляете, что 1000 подходит - не слишком большой, не слишком маленький - безо всяких догадок.В программировании часто догадываюсь == сбой.Или, что еще хуже, без сбоев.

Кстати, 2, вы delete используете автоматическую переменную выше.Ты этого не делаешь.Используйте delete тогда и только тогда, когда вы используете new.Вы не new, так что не delete.

Кстати, 3, если вы просто хотите извлечь весь поток в строку, вы можете просто сделать это:

string s = SomeIStream.str();
...