пятница, 13 января 2012 г.

Шустрая замена Stringstream или немного о Boost Lexical_cast на русском

Всем нам так или иначе приходилось сталкиваться с задачей конвертации данных  из одного типа в другой, например из string в int или на оборот. Для решения таких задач стандартная библиотека предоставляет несколько инструментов, таких как scanf/sprintf или же std::stringstream.
И казалось бы хватит, но нет есть и другие такие как boost::lexical_cast, продолжаем изучать библиотеку boost. Давайте попробуем разобраться чем же он лучше/хуже стандартных.



Исчерпывающая информация на англ. есть здесь. И вот какие доводы они предоставляют:
 - стандартная библиотека Си имеет функцию atoi которая производить конвертацию только в одном направлении из текста в другие типы.
 - Использование sprintf считается небезопасным.
 - itoa является платформозависимой
 - Стандартная библиотека позволяет конвертировать в типы intlong, и double.
 - scanf предлагает много возможностей для преобразования, но считается небезопасным
 - Стандартная библиотека С++ предлагает stringstream - является гибким и безопасным инструментом, но интерфейс которого практически заставляет программиста вводит дополнительные переменные.


boost::lexical_cast - является гибким и безопасным инструментом конвертации интерфейс которого удобней stringstream, к тому же lexical_cast быстрее stringstream, убедится в этом можно посмотрев таблицу ниже.


А пока немного примеров:
Данный пример преобразовывает параметры командной строки в переменные типа short:

int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector<short> args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast<short>(*argv));
        }
        catch(bad_lexical_cast &)
        {
            args.push_back(0);
        }
    }
    ...
}



В этом примере числа используются как строки:
void log_message(const std::string &);

void log_errno(int yoko)
{
    log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
}

Все тесты проводились на 10000 итераций следующих блоков кода, время в мс:

Table 14.1. Tests source code
Test name
Code
lexical_cast
_out = boost::lexical_cast<OUTTYPE>(_in);
std::stringstream with construction
std::stringstream ss;
ss << _in;
if (ss.fail()) throw std::logic_error(descr);
ss >> _out;
if (ss.fail()) throw std::logic_error(descr);
std::stringstream without construction
ss << _in; // ss экземпляр std::stringstream
if (ss.fail()) throw std::logic_error(descr);
ss >> _out;
if (ss.fail()) throw std::logic_error(descr);
/* сброс std::stringstream для повторного использования */
ss.str(std::string());
ss.clear();
scanf/printf
typename OUTTYPE::value_type buffer[500];
sprintf( (char*)buffer, conv, _in);
_out = buffer;
Лучшие результаты выделены так "!!! результат !!!", тут есть тесты для разных компиляторов, а здесь только для GCC-4.4:


Table 14.3. Performance Table (gcc-4.4)
From->To
lexical_cast
std::stringstream with construction
std::stringstream without construction
scanf/printf
string->char
!!! <1 !!!
90
7
7
string->signed char
!!! <1 !!!
88
7
8
string->unsigned char
!!! <1 !!!
88
8
14
string->int
!!! 3 !!!
103
18
15
string->short
!!! 3 !!!
105
20
15
string->long int
!!! 3 !!!
101
18
16
string->long long
!!! 3 !!!
101
18
15
string->unsigned int
!!! 3 !!!
98
23
14
string->unsigned short
!!! 3 !!!
100
17
14
string->unsigned long int
!!! 3 !!!
100
21
15
string->unsigned long long
!!! 3 !!!
99
19
15
string->bool
!!! <1 !!!
95
16
8
string->float
!!! 13 !!!
160
61
33
string->double
!!! 14 !!!
206
93
59
string->long double
128
217
96
!!! 61 !!!
char->string
!!! 7 !!!
100
17
12
unsigned char->string
!!! 7 !!!
109
17
16
signed char->string
!!! 7 !!!
99
17
12
int->string
!!! 13 !!!
110
21
15
short->string
!!! 14 !!!
110
22
17
long int->string
!!! 14 !!!
109
21
16
long long->string
!!! 13 !!!
114
20
17
unsigned int->string
!!! 13 !!!
109
23
15
unsigned short->string
!!! 14 !!!
109
23
17
unsigned long int->string
!!! 13 !!!
112
23
16
unsigned long long->string
!!! 14 !!!
109
21
17
bool->string
!!! 7 !!!
108
23
11
float->string
63
185
92
!!! 50 !!!
double->string
106
216
116
!!! 75 !!!
long double->string
118
219
119
!!! 80 !!!
char*->char
!!! 1 !!!
93
9
9
char*->signed char
!!! 1 !!!
92
9
9
char*->unsigned char
!!! 1 !!!
92
9
14
char*->int
!!! 4 !!!
107
19
15
char*->short
!!! 5 !!!
109
19
15
char*->long int
!!! 4 !!!
113
19
15
char*->long long
!!! 4 !!!
108
20
15
char*->unsigned int
!!! 4 !!!
106
19
15
char*->unsigned short
!!! 4 !!!
106
18
15
char*->unsigned long int
!!! 4 !!!
103
22
15
char*->unsigned long long
!!! 4 !!!
105
20
15
char*->bool
!!! 1 !!!
104
18
8
char*->float
!!! 15 !!!
164
62
33
char*->double
!!! 16 !!!
203
97
58
char*->long double
132
223
98
!!! 60 !!!
unsigned char*->char
!!! 2 !!!
90
9
8
unsigned char*->signed char
!!! 2 !!!
92
10
8
unsigned char*->unsigned char
!!! 2 !!!
91
9
14
unsigned char*->int
!!! 6 !!!
106
20
15
unsigned char*->short
!!! 6 !!!
106
21
15
unsigned char*->long int
!!! 6 !!!
111
19
15
unsigned char*->long long
!!! 6 !!!
107
20
15
unsigned char*->unsigned int
!!! 6 !!!
105
19
15
unsigned char*->unsigned short
!!! 6 !!!
103
18
15
unsigned char*->unsigned long int
!!! 6 !!!
106
22
14
unsigned char*->unsigned long long
!!! 6 !!!
105
20
14
unsigned char*->bool
!!! 2 !!!
106
18
8
unsigned char*->float
!!! 15 !!!
167
68
33
unsigned char*->double
!!! 17 !!!
203
99
58
unsigned char*->long double
129
216
97
!!! 61 !!!
unsigned char*->string
!!! 13 !!!
111
23
---
signed char*->char
!!! 2 !!!
92
9
8
signed char*->signed char
!!! 2 !!!
91
9
8
signed char*->unsigned char
!!! 2 !!!
91
9
14
signed char*->int
!!! 6 !!!
107
19
15
signed char*->short
!!! 6 !!!
109
24
14
signed char*->long int
!!! 6 !!!
112
19
15
signed char*->long long
!!! 5 !!!
107
20
15
signed char*->unsigned int
!!! 6 !!!
108
20
15
signed char*->unsigned short
!!! 6 !!!
104
18
15
signed char*->unsigned long int
!!! 6 !!!
102
22
15
signed char*->unsigned long long
!!! 6 !!!
104
20
15
signed char*->bool
!!! 2 !!!
104
18
8
signed char*->float
!!! 16 !!!
165
63
33
signed char*->double
!!! 16 !!!
203
98
59
signed char*->long double
129
215
98
!!! 61 !!!
signed char*->string
!!! 13 !!!
109
21
---
int->int
!!! <1 !!!
109
21
---
float->double
!!! <1 !!!
221
102
---
double->double
!!! <1 !!!
223
103
---
int->int
!!! <1 !!!
231
115
---
int->int
!!! <1 !!!
231
115
---
char->unsigned char
!!! <1 !!!
92
8
---
char->signed char
!!! <1 !!!
88
8
---
unsigned char->char
!!! <1 !!!
88
7
---
signed char->char
!!! <1 !!!
89
8
---





Комментариев нет:

Отправить комментарий