Не то чтобы я большой любитель C++, тем не менее всегда считал что форматирование через stringstream работает быстрее чем форматирование через sprintf. В очередной раз обсудив плюсы и минусы форматирования с коллегами, решили что проще “достать да померять”. Итог оказался довольно неожиданный для меня: stringstream позорно слил в лучшем случае в 2 раза, а в худшем в 3!
Вариант на C:
#include <sys/time.h>
#include <stdio.h>
int main()
{
int a = 256;
int b = 0xbaadf00d;
float c = 3.1415926535;
char d[] = "17 symbols string";
int i;
struct timeval time;
gettimeofday(&time, NULL);
for (i = 0; i < 0x100000; ++i)
{
char buffer[1024];
sprintf(buffer, "%010d %X %+*.*f %.5s", a, b, 3, 2, c, d);
}
struct timeval time1;
gettimeofday(&time1, NULL);
printf("%i", ((time1.tv_sec * 1000) + (time1.tv_usec / 1000)) - ((time.tv_sec * 1000) + (time.tv_usec / 1000)));
}
#include <stdio.h>
int main()
{
int a = 256;
int b = 0xbaadf00d;
float c = 3.1415926535;
char d[] = "17 symbols string";
int i;
struct timeval time;
gettimeofday(&time, NULL);
for (i = 0; i < 0x100000; ++i)
{
char buffer[1024];
sprintf(buffer, "%010d %X %+*.*f %.5s", a, b, 3, 2, c, d);
}
struct timeval time1;
gettimeofday(&time1, NULL);
printf("%i", ((time1.tv_sec * 1000) + (time1.tv_usec / 1000)) - ((time.tv_sec * 1000) + (time.tv_usec / 1000)));
}
Вариант на C++:
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <sys/time.h>
using namespace std;
int main()
{
int a = 256;
int b = 0xbaadf00d;
float c = 3.1415926535;
char d[] = "17 symbols string";
timeval time;
gettimeofday(&time, NULL);
for (i = 0; i < 0x100000; ++i)
{
stringstream stream;
stream << setfill('0') << setw(10) << a << " "
<< hex << uppercase << b << " "
<< showpos << setprecision(3) << c << " "
<< string(d, d+5);
}
timeval time1;
gettimeofday(&time1, NULL);
cout << ((time1.tv_sec * 1000) + (time1.tv_usec / 1000)) - ((time.tv_sec * 1000) + (time.tv_usec / 1000));
}
#include <sstream>
#include <iostream>
#include <iomanip>
#include <sys/time.h>
using namespace std;
int main()
{
int a = 256;
int b = 0xbaadf00d;
float c = 3.1415926535;
char d[] = "17 symbols string";
timeval time;
gettimeofday(&time, NULL);
for (i = 0; i < 0x100000; ++i)
{
stringstream stream;
stream << setfill('0') << setw(10) << a << " "
<< hex << uppercase << b << " "
<< showpos << setprecision(3) << c << " "
<< string(d, d+5);
}
timeval time1;
gettimeofday(&time1, NULL);
cout << ((time1.tv_sec * 1000) + (time1.tv_usec / 1000)) - ((time.tv_sec * 1000) + (time.tv_usec / 1000));
}
Твоя программа ускоряется в два раза если не создавать тяжелые объекты на каждой итерации цикла:
string str( d, d + 5 );
ostringstream stream;
stream.precision(3);
stream.fill('0');
for (int i = 0; i < 0x100000; ++i)
{
stream << setw(10) << a << " "
<< hex << uppercase << b << " "
<< showpos << c << " " << str;
stream.str("");
}
тогда эксперимент будет не чистым. дело в том, что была попытка сравнить скорость в условиях приближенных к реальным. Ну а в реале ты явно не будешь создавать единственный объект класса stringstream и организовывать к нему доступ из всех частей программы
stringstream медленный. это факт.
На самом деле его можно ускорить, но в реализации MS VC с этим не заморачиваются.
Я как-то смотрел, там в общем, имеет место аллокации в ненужных местах. Которые вполне можно заменить на аллокацию на стеке: boost::optional / placement new .
Потом совсем дикий способ форматирования, видимо из-за требований к стандарту..
В итоге чуть ли не на каждое число вызываем new, и передаем в sprintf
Если нужна скорость, и не нужен поток.
http://www.fastformat.org или sprintf.
С другой стороны, у каждого разные возможности, поэтому нужно оценивать что важнее.
Я тут поглядел примеры на http://www.fastformat.org и они меня несколько разочаровали. Такое ощущение, что все хорошо пока тебе надо вывести значение в представлении "по умолчанию". А вот повторить то, что у меня в примере выше ну никак не представляется возможным.
Зато инфа про буст порадовала – всегда считал их реализацию тормозным монстром
Да, boost::format это тормоз еще тот.
Зато он умеет очень много.
Ну вот и пришли.
Либо выбираем скорость либо фичи.
Кстати, самый лучший вариант это какой-нибудь compile time printf.
Типа
mysprintf< описываем строку > ( передаем аргументы )
Тогда и проверка типов и можно сразу sprintf с нужными аргументами вызвать.
так по сочетанию скорость/фичи sprintf всех рвет как тузик грелку
У него нет другой расширяемости.
Нельзя boost::tuple вывести в sprintf с такой же легкостью как в ostream.
Нубское сравнение какое-то.
Две абсолютные разные системы вывода.
Для начала выделяйте буфер динамически. Во-вторых не забываем что потоки работают с объектами локалей. В третьих принтф не расширяемое и не безопасное решение, о каких фитчах речь?
boost::format универсальное решение, объединяющее оба интерфейса, но как и любое универсальное решение медленее обоих.