намаляване на размера на поток от низове

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

Моят проблем сега е, че този поток от низове нараства по размер за неопределено време. Опитах няколко неща, за да се уверя, че запазвам само последните около 1 MiB от потока, но не успях.

  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 и ще създава няколко GiB данни на ден. Както и да е, всъщност не се нуждая от целия този дневник - интересуват ме само последните няколко минути (или секунди) преди срив.   -  person example    schedule 12.09.2013
comment
Има принцип, наречен ротация на трупи, който звучи приложим. Запазвате един или два стари и един текущ лог-файл. На всеки X единици време променяте текущия на един от по-старите и изтривате най-стария. В linux дори има инструменти, които да направят това вместо вас, стига отпечатването на журнал да отваря и затваря файла достатъчно често (ако файлът се държи отворен през ЦЯЛОТО време, вие просто продължавате да пишете в стария файл, който е бил изтрит, защото така работят файловите системи в стил Unix).   -  person Mats Petersson    schedule 12.09.2013
comment
Дискът е евтин, паметта не. Често срещан дизайн за регистраторите е използването на подвижни файлове. Когато надвишите определен размер, вие затваряте и преименувате индекс на файлове, изпускайки или архивирайки най-стария, след което отваряте нов. Това би било идеално конфигурируемо. За телекомуникационен сървър, който внедрих, който също работи 24/7, буквално отпечатах всеки вход и изход за всеки метод на всяка нишка и открих, че 20 файла по 25MB всеки бяха повече от достатъчни, за да проследя всеки проблем за повечето сайтове.   -  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 дневник. И наистина искаш да ми кажеш, че някои MiB ram са по-скъпи от Gigs hdd? Освен това намирам това решение за малко грозно. По моя начин щях да автоматизирам хубави съобщения за грешка, включително обратно проследяване и собствен дневник на това, което програмата е правила преди всяка грешка. Но нека пренебрегнем тази грешка за момент. Бих искал да знам начин да спра поток от низове да агрегира вече премахнатите данни без край, независимо от този конкретен случай на употреба.   -  person example    schedule 12.09.2013
comment
Можете да приспособите условията според вашите нужди. Предложението на Mats за използване на интервали от време и хвърляне на всички освен най-новите може да ви хареса повече. Повечето 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