уменьшение размера струнного потока

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

Моя проблема сейчас в том, что этот струнный поток неограниченно увеличивается в размерах. Я пробовал несколько вещей, чтобы гарантировать, что я сохраняю только последний 1 МБ или около того потока, но безуспешно.

  1. .rdbuf()->pubseekoff(...)
  2. .ignore(...)
  3. getline(...)
  4. ss.str() = ss.str().substr(...)

Очевидно, что базовый буферный объект всегда только увеличивается в размере - независимо от того, были ли уже прочитаны некоторые данные или нет.

Есть ли способ уменьшить размер / удерживать его на каком-то постоянном уровне (желательно без обычных глубоких копий)? Круговой буфер в качестве базового объекта буфера был бы идеальным - возможно ли это? Esp. это уже существует?


РЕДАКТИРОВАТЬ: Решение в основном должно вести себя как поток. Он размещается компилятором вместо std :: err или прямого файлового потока (аналогично boost :: log). Следовательно, использование строкового потока не является строго необходимым, но очень полезным. (В противном случае мне пришлось бы реализовать все вещи ostream, чтобы иметь возможность передавать std :: endl ...)


person example    schedule 11.09.2013    source источник
comment
Рассматривали ли вы просто использовать std::ofstream и вместо этого напрямую выполнять сброс в файл журнала?   -  person AJG85    schedule 12.09.2013
comment
@ AJG85 Он становится слишком большим. Программа должна работать 24/7 и создавать несколько гигабайт данных в день. В любом случае мне не нужен весь этот журнал - меня интересуют только последние несколько минут (или секунд) до сбоя.   -  person example    schedule 12.09.2013
comment
Есть принцип, называемый ротацией журналов, который звучит применимо. Вы храните один или два старых и один текущий лог-файлы. Каждые X единиц времени вы меняете текущий на один из более старых и удаляете самый старый. В linux есть даже инструменты, чтобы сделать это за вас, если печать журнала открывается и закрывает файл достаточно часто (если файл остается открытым ВСЕГДА, вы просто продолжаете писать в старый файл, который был удален, потому что так работают файловые системы в стиле Unix).   -  person Mats Petersson    schedule 12.09.2013
comment
Диск дешевый, памяти нет. Обычная конструкция для регистраторов - использование файлов с возможностью прокрутки. Когда вы превышаете определенный размер, вы закрываете и переименовываете индекс файлов, удаляя или архивируя самые старые, а затем открываете новый. В идеале это можно было бы настроить. Для телекоммуникационного сервера, который я реализовал, который также работал 24/7, я буквально распечатал каждую запись и выход для каждого метода каждого потока и обнаружил, что 20 файлов по 25 МБ каждый был более чем достаточно, чтобы отслеживать любую проблему для большинства сайтов.   -  person AJG85    schedule 12.09.2013
comment
@MatsPetersson Я вижу, ты быстрее машинистка ;-)   -  person AJG85    schedule 12.09.2013
comment
@ AJG85: У меня годы практики!   -  person Mats Petersson    schedule 12.09.2013
comment
@ AJG85 Мне действительно нужно всего несколько мегабайт журнала. А вы правда хотите мне сказать, что некоторые MiB RAM дороже гигов hdd? Кроме того, я считаю это решение несколько уродливым. По-своему я бы автоматизировал приятные сообщения об ошибках, включая обратную трассировку и мой собственный журнал того, что программа делала до каждой ошибки. Но давайте на мгновение проигнорируем этот фон ошибки. Я хотел бы знать, как запретить строковому потоку агрегировать уже удаленные данные без конца, независимо от этого конкретного варианта использования.   -  person example    schedule 12.09.2013
comment
Вы можете адаптировать условия под себя. Возможно, вам больше понравится предложение ковриков использовать интервалы времени и подбрасывать все, кроме самого последнего. Большинство объектов STL спроектированы таким образом, чтобы их емкость увеличивалась в течение срока их службы, но я считаю, что вы можете использовать oss.str(""); oss.clear(); для сброса.   -  person AJG85    schedule 12.09.2013
comment
Если вам нужен поток строк с циклической буферизацией, я думаю, вам нужно написать свой собственный streambuf.   -  person Adam Burry    schedule 12.09.2013
comment
Возможный дубликат: stackoverflow .com / questions / 6370301 /.   -  person namezero    schedule 12.09.2013


Ответы (1)


В моей текущей реализации STL (VS2010 SP1) str ("") освобождает всю память

std::stringstream ss;
for(unsigned int i = 0; i<10000000; ++i)
{
    ss << "QWERTYUIOPASDFGHJKLXCVBNM";
}

ss.str(""); // memory released here

Ссылка: «Внутренне функция вызывает элемент str своего внутреннего строкового буфера. объект."

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

person namezero    schedule 12.09.2013
comment
Я по ошибке позвонил ss.str() = , предполагая, что .str() возвращает ссылку .... Я все еще думаю, что даже .str("") не освобождает память в моей реализации (gcc 4.8), но стандарт мог предполагать, что память должна быть освобождена (некоторые реализации делают это) . Итак, ваш ответ технически правильный (я его принимаю), хотя мне пришлось в конце концов реализовать ротацию нескольких строковых потоков ... - person example; 28.01.2014
comment
Странно, что память не должна освобождаться тогда на gcc. Сброс объекта также сбросит смещения чтения и записи. Единственная возможность была бы, если бы базовый streambuf каким-то образом удерживал память, потому что внешняя абстракция действительно сообщает 0 после сброса; см. здесь: coliru.stacked-crooked.com/a/d66fbc86e6c1c220 Конечно, вызов pbase () было бы более значимым для этого. Я рад, что ты решил свою проблему! - person namezero; 29.01.2014
comment
@Nikos Да, но намерение OP состояло в том, чтобы освободить неиспользуемую память при переработке объекта строкового потока. - person namezero; 17.09.2019