从 unsigned char 的 std::span 创建 std::string
Create std::string from std::span of unsigned char
我正在使用一个 C 库,它使用各种固定大小的 unsigned char
数组,没有空终止符作为字符串。
我一直在使用以下函数将它们转换为 std::string
:
auto uchar_to_stdstring(const unsigned char* input_array, int width) -> std::string {
std::string temp_string(reinterpret_cast<const char*>(input_array), width);
temp_string.erase(temp_string.find_last_not_of(' ') + 1);
return temp_string;
}
除了使用 reinterpret_cast
之外,它工作正常,需要传递数组大小以及我正在将数组衰减为指针这一事实。我试图通过使用 std::span
.
来避免所有这些问题
使用 std::span
的函数如下所示:
auto ucharspan_to_stdstring(const std::span<unsigned char>& input_array) -> std::string {
std::stringstream temp_ss;
for (const auto& input_arr_char : input_array) {
temp_ss << input_arr_char;
}
return temp_ss.str();
}
该函数运行良好,使其他一切变得更简单,而无需跟踪 C 数组的大小。但是,通过一些基准测试(使用 nanobench)进一步挖掘表明新函数比经典的 reinterpret_cast
方法慢很多倍。我的假设是基于 std::span
的函数中的 for
循环是这里的低效率。
我的问题: 是否有更有效的方法将固定大小的 C 无符号字符数组从 std::span
变量转换为 std::string
?
编辑:
gcc
基准测试(-O3 -DNDEBUG -std=gnu++20,nanobench,minEpochIterations=54552558,warmup=100,doNotOptimizeAway)
relative
ns/op
op/s
err%
ins/op
bra/op
miss%
total
uchar[] to std::string
100.0%
5.39
185,410,438.12
0.3%
80.00
20.00
0.0%
3.56
uchar
2.1%
253.06
3,951,678.30
0.6%
4,445.00
768.00
0.0%
167.74
ucharspan
1,244.0%
0.43
2,306,562,499.69
0.2%
9.00
1.00
0.0%
0.29
ucharspan_barry
72.8%
7.41
134,914,127.56
1.3%
99.00
22.00
0.0%
4.89
uchar_bsv
clang
基准测试(-O3 -DNDEBUG -std=gnu++20,nanobench,minEpochIterations=54552558,warmup=100,doNotOptimizeAway)
relative
ns/op
op/s
err%
ins/op
bra/op
miss%
total
uchar[] to std::string
100.0%
2.13
468,495,014.11
0.2%
14.00
1.00
0.0%
1.42
uchar
0.8%
251.74
3,972,418.54
0.2%
4,477.00
767.00
0.0%
166.30
ucharspan
144.4%
1.48
676,329,668.07
0.1%
7.00
0.00
95.8%
0.98
ucharspan_barry
34.5%
6.19
161,592,563.70
0.1%
80.00
24.00
0.0%
4.08
uchar_bsv
(uchar_bsv
在基准测试中与 ucharspan_barry
相同,但使用 std::basic_string_view<unsigned char const>
参数而不是 std::span<unsigned char const>
你想要:
auto ucharspan_to_stdstring(std::span<unsigned char const> input_array) -> std::string {
return std::string(input_array.begin(), input_array.end());
}
string
与其他标准库容器一样,可以从适当的迭代器对构造 - 这就是这样的一对。由于这些是随机访问迭代器,这将进行一次分配等。
请注意,出于两个原因,我从 span<T> const&
更改为 span<T const>
。首先,您没有改变 span 的内容,因此内部类型需要是 const
... 类似于您使用 T const*
而不是 T*
的方式。其次,您应该按值获取 span
s,因为它们的复制成本很低(除非您非常特别需要跨度的标识,而您在这里不需要)。
做一个 reinterpret_cast
可能更好,这样你就可以使用 (char const*, size_t)
构造函数——这个构造函数确保了单个 memcpy
用于最终写入。但你必须花时间看看它是否值得。
我正在使用一个 C 库,它使用各种固定大小的 unsigned char
数组,没有空终止符作为字符串。
我一直在使用以下函数将它们转换为 std::string
:
auto uchar_to_stdstring(const unsigned char* input_array, int width) -> std::string {
std::string temp_string(reinterpret_cast<const char*>(input_array), width);
temp_string.erase(temp_string.find_last_not_of(' ') + 1);
return temp_string;
}
除了使用 reinterpret_cast
之外,它工作正常,需要传递数组大小以及我正在将数组衰减为指针这一事实。我试图通过使用 std::span
.
使用 std::span
的函数如下所示:
auto ucharspan_to_stdstring(const std::span<unsigned char>& input_array) -> std::string {
std::stringstream temp_ss;
for (const auto& input_arr_char : input_array) {
temp_ss << input_arr_char;
}
return temp_ss.str();
}
该函数运行良好,使其他一切变得更简单,而无需跟踪 C 数组的大小。但是,通过一些基准测试(使用 nanobench)进一步挖掘表明新函数比经典的 reinterpret_cast
方法慢很多倍。我的假设是基于 std::span
的函数中的 for
循环是这里的低效率。
我的问题: 是否有更有效的方法将固定大小的 C 无符号字符数组从 std::span
变量转换为 std::string
?
编辑:
gcc
基准测试(-O3 -DNDEBUG -std=gnu++20,nanobench,minEpochIterations=54552558,warmup=100,doNotOptimizeAway)
relative | ns/op | op/s | err% | ins/op | bra/op | miss% | total | uchar[] to std::string |
---|---|---|---|---|---|---|---|---|
100.0% | 5.39 | 185,410,438.12 | 0.3% | 80.00 | 20.00 | 0.0% | 3.56 | uchar |
2.1% | 253.06 | 3,951,678.30 | 0.6% | 4,445.00 | 768.00 | 0.0% | 167.74 | ucharspan |
1,244.0% | 0.43 | 2,306,562,499.69 | 0.2% | 9.00 | 1.00 | 0.0% | 0.29 | ucharspan_barry |
72.8% | 7.41 | 134,914,127.56 | 1.3% | 99.00 | 22.00 | 0.0% | 4.89 | uchar_bsv |
clang
基准测试(-O3 -DNDEBUG -std=gnu++20,nanobench,minEpochIterations=54552558,warmup=100,doNotOptimizeAway)
relative | ns/op | op/s | err% | ins/op | bra/op | miss% | total | uchar[] to std::string |
---|---|---|---|---|---|---|---|---|
100.0% | 2.13 | 468,495,014.11 | 0.2% | 14.00 | 1.00 | 0.0% | 1.42 | uchar |
0.8% | 251.74 | 3,972,418.54 | 0.2% | 4,477.00 | 767.00 | 0.0% | 166.30 | ucharspan |
144.4% | 1.48 | 676,329,668.07 | 0.1% | 7.00 | 0.00 | 95.8% | 0.98 | ucharspan_barry |
34.5% | 6.19 | 161,592,563.70 | 0.1% | 80.00 | 24.00 | 0.0% | 4.08 | uchar_bsv |
(uchar_bsv
在基准测试中与 ucharspan_barry
相同,但使用 std::basic_string_view<unsigned char const>
参数而不是 std::span<unsigned char const>
你想要:
auto ucharspan_to_stdstring(std::span<unsigned char const> input_array) -> std::string {
return std::string(input_array.begin(), input_array.end());
}
string
与其他标准库容器一样,可以从适当的迭代器对构造 - 这就是这样的一对。由于这些是随机访问迭代器,这将进行一次分配等。
请注意,出于两个原因,我从 span<T> const&
更改为 span<T const>
。首先,您没有改变 span 的内容,因此内部类型需要是 const
... 类似于您使用 T const*
而不是 T*
的方式。其次,您应该按值获取 span
s,因为它们的复制成本很低(除非您非常特别需要跨度的标识,而您在这里不需要)。
做一个 reinterpret_cast
可能更好,这样你就可以使用 (char const*, size_t)
构造函数——这个构造函数确保了单个 memcpy
用于最终写入。但你必须花时间看看它是否值得。