Есть ли способ уменьшить ostringstream malloc/free?

Я пишу встроенное приложение. В некоторых местах я часто использую std::ostringstream, так как это очень удобно для моих целей. Однако я только что обнаружил, что производительность сильно снижается, поскольку добавление данных в поток приводит к большому количеству вызовов malloc и free. Есть ли способ избежать этого?

Моей первой мыслью было сделать ostringstream статическим и сбросить его с помощью ostringstream::set(""). Однако это невозможно сделать, так как мне нужно, чтобы функции были реентерабельными.


person Johan Kotlinski    schedule 01.03.2010    source источник
comment
Dupe stackoverflow.com/questions/1941064/   -  person Johan Kotlinski    schedule 01.03.2010
comment
Хм... вопрос с обманом не дает действительного ответа.   -  person Johan Kotlinski    schedule 01.03.2010
comment
Кроме того, обман заранее предполагает ответ.   -  person MSalters    schedule 02.03.2010


Ответы (4)


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

Хотя не всегда. Мы не можем использовать его (или ostringstream) в моей работе в реальном времени после инициализации, потому что оба они выполняют выделение и освобождение памяти.

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

В качестве более общего решения вы можете рассмотреть возможность написания собственной версии ostringstream, которая использует буфер фиксированного размера (конечно, с проверкой ошибок в границах). Это потребует немного усилий, но если у вас много таких потоковых операций, оно того стоит.

person T.E.D.    schedule 01.03.2010
comment
Я начал было добавлять, но отказался. Я пойду вперед и вставлю это для вас. - person T.E.D.; 01.03.2010
comment
Вы могли бы по крайней мере использовать snprintf (с буфером стека), но я все равно не стал бы его поддерживать, если только профилирование не покажет, что оно дает вам необходимые преимущества, и вы решите, что недостатки стоят того, чтобы его использовать. - person Mark B; 01.03.2010
comment
Я не проверял snprintf, но подозреваю, что у него будет та же недетерминированная проблема, что и у sprintf на нашей платформе. Если подумать, ни один из них не должен выполнять динамическое выделение памяти... но наш sprintf делает это. :-( - person T.E.D.; 02.03.2010
comment
Профилирование определенно показывает, что malloc/free в нашей системе безумно дороги, мы сталкивались с этим раньше... - person Johan Kotlinski; 02.03.2010

Если вы знаете, насколько велики данные перед созданием потока, вы можете использовать ostrstream, конструктор которого может принимать буфер в качестве параметра. Таким образом не будет никакого управления памятью данных.

person mmmmmm    schedule 01.03.2010

Вероятно, одобренным способом решения этой проблемы будет создание собственного объекта basic_stringbuf для использования с вашим ostringstream. Для этого у вас есть несколько вариантов. Одним из них было бы использование буфера фиксированного размера, и overflow просто терпит неудачу, когда/если вы пытаетесь создать слишком длинный вывод. Другой возможностью было бы использование вектора в качестве буфера. В отличие от std::string, vector гарантирует, что добавляемые данные будут иметь амортизированную постоянную сложность. Он также никогда не выпускает данные из буфера, если вы не принуждаете его к этому, поэтому он обычно увеличивается до максимального размера, с которым вы имеете дело. С этого момента он не должен выделять или освобождать память, если вы не создадите строку, длина которой превышает доступную в настоящее время длину.

person Jerry Coffin    schedule 01.03.2010
comment
Я проверил источник реализации STL, который я использую, если я передам ему строку конструктору ostringstream, он просто сделает копию этой строки... - person Johan Kotlinski; 01.03.2010
comment
Да, я ожидал этого. Я бы посоветовал создать свой собственный объект stringbuf и присоединить к нему поток. - person Jerry Coffin; 01.03.2010
comment
Если вы хотите передать используемый буфер ostrstream, а не ostringstream - person mmmmmm; 04.03.2010
comment
@Марк: Может быть. Если вам действительно нужен буфер фиксированного размера, это разумная возможность. Однако это даже не близко к замене того, который использует vector<char> в качестве буфера. - person Jerry Coffin; 04.03.2010
comment
Правда, но ответ дал буфер фиксированного размера - person mmmmmm; 05.03.2010
comment
@mark: как одна из возможностей, но это также дало возможность вектору. Честно говоря, даже если вам нужен фиксированный буфер, я не уверен, что strstreams — лучший ответ. Они включены исключительно для обратной совместимости, но устарели с первого дня. - person Jerry Coffin; 05.03.2010

std::ostringsteam — это удобный интерфейс. Он связывает std::string с std::ostream, предоставляя пользовательский std::streambuf. Вы можете реализовать свой собственный std::streambuf. Это позволяет вам выполнять все управление памятью. Вы по-прежнему получаете хорошее форматирование std::ostream, но у вас есть полный контроль над управлением памятью. Конечно, последствием этого является то, что вы получаете отформатированный вывод в формате char[], но это, вероятно, не является большой проблемой, если вы являетесь разработчиком встраиваемых систем.

person MSalters    schedule 02.03.2010
comment
Это руководство было полезно для реализации пользовательского std::streambuf mr-edd.co.uk/ блог/beginners_guide_streambuf - person Brian W.; 19.09.2013