Всем нам так или иначе приходилось сталкиваться с задачей конвертации данных из одного типа в другой, например из string в int или на оборот. Для решения таких задач стандартная библиотека предоставляет несколько инструментов, таких как scanf/sprintf или же std::stringstream.
И казалось бы хватит, но нет есть и другие такие как boost::lexical_cast, продолжаем изучать библиотеку boost. Давайте попробуем разобраться чем же он лучше/хуже стандартных.
Исчерпывающая информация на англ. есть здесь. И вот какие доводы они предоставляют:
- стандартная библиотека Си имеет функцию atoi которая производить конвертацию только в одном направлении из текста в другие типы.
- Использование sprintf считается небезопасным.
- itoa является платформозависимой
- Стандартная библиотека позволяет конвертировать в типы
- scanf предлагает много возможностей для преобразования, но считается небезопасным
- Стандартная библиотека С++ предлагает stringstream - является гибким и безопасным инструментом, но интерфейс которого практически заставляет программиста вводит дополнительные переменные.
boost::lexical_cast - является гибким и безопасным инструментом конвертации интерфейс которого удобней stringstream, к тому же lexical_cast быстрее stringstream, убедится в этом можно посмотрев таблицу ниже.
А пока немного примеров:
Данный пример преобразовывает параметры командной строки в переменные типа short:
Лучшие результаты выделены так "!!! результат !!!", тут есть тесты для разных компиляторов, а здесь только для GCC-4.4:
И казалось бы хватит, но нет есть и другие такие как boost::lexical_cast, продолжаем изучать библиотеку boost. Давайте попробуем разобраться чем же он лучше/хуже стандартных.
Исчерпывающая информация на англ. есть здесь. И вот какие доводы они предоставляют:
- стандартная библиотека Си имеет функцию atoi которая производить конвертацию только в одном направлении из текста в другие типы.
- Использование sprintf считается небезопасным.
- itoa является платформозависимой
- Стандартная библиотека позволяет конвертировать в типы
int
, long
, и 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; |
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
|
---
|
Комментариев нет:
Отправить комментарий