精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
锐英源精品开源心得,禁止全文或局部转载,禁止任何形式的非法使用,侵权必究
本文介绍C++17知识点的名称,不讲解大多细节,只讲解C++性能提升关键点示例。因为我最近写的项目,很多线程,想要提升性能。所以叫:C++17归类引导、C++17性能提升关键点示例。
C++17归类有:
结构结合
带有初始值设定项的 'if' 和 'switch' 语句
Constexpr lambda 并按值捕获 *this
if constexpr
__has_include
使用不重复的属性命名空间
属性 'nodiscard', 'fallthrough', 'maybe_unused'
std::string_view
嵌套的 'namespaces'
字符串转换
过度对齐的动态内存分配
折叠表达式
'inline' 变量
库添加
文件系统
并行算法
C++性能提升关键点中重要的有字符串转换和并行算法,这里对字符串转换进行示例讲解,因为字符串是最常用的功能。
当然,在以前的 C++ 标准中,总是有字符串转换函数,比如:std::atoi, std::atol, std::atoll, std::stoi, std::stol, std::stoll, std::sprintf, std::snprintf, std::stringstream, std::sscanf, std::strtol, std::strtoll, std::stringstream, std::to_string遗憾的是,这些功能在性能方面不够有效。
一般认为,上述函数对于复杂字符串的处理,例如对于复杂数据格式(如 JSON 或 XML)的高效处理,速度较慢。
特别是当此类数据格式用于通过网络进行通信时,其中高带宽是一个关键因素。
在 C++17 中,我们得到了两组函数:from_chars和to_chars,它们允许低级字符串转换并显著提高性能。
例如,Microsoft 报告说 C++17 已针对科学记数法进行了改进,它的floating-point to_chars()速度大约是 sprintf_s() “%.8e” 的 10 倍,是 sprintf_s() “%.16e”处理double 的 30 倍。这使用了Ulf Adams的新算法 Ryu。
注意:如果您使用的是 Visual Studio 2017,则需要确保已安装 15.8 或更早版本,因为版本 15.7(具有第一个完整的 C++17 库支持)不支持 <charconv> 标头。
让我们看一个例子,了解如何使用 ,使用 ,将字符串转换为整数和浮点数:std::from_chars
#include <iostream> #include <string> #include <array> #include <charconv> // from_chars int main() { std::cout << "---------------------------------------------------------------------------------------------------\n"; std::cout << "Let's demonstrate string conversion to integer using the 'std::from_chars' function " << std::endl; std::cout << "---------------------------------------------------------------------------------------------------\n"; std::array<std::string, 8> arrIntNums = { std::string("-123"), std::string("-1234"), std::string("-12345"), std::string("-1234567890987654321"), std::string("123"), std::string("1234"), std::string("1234567890"), std::string("1234567890987654321")};//8是数组长度 int stored_int_value { 0 }; for (auto& e : arrIntNums) { std::cout << "Array element = " << e << std::endl; const auto res = std::from_chars(e.data(), e.data() + e.size(), stored_int_value /*, int base = 10*/); switch (res.ec) { case std::errc(): //from_chars的结果是复杂类型,不是直接数值类型 std::cout << "Stored value: " << stored_int_value << ", Number of characters = " << res.ptr - e.data() << std::endl;//正常状态,输出结果 break; case std::errc::result_out_of_range: std::cout << "Result out of range! Number of characters = " << res.ptr - e.data() << std::endl; break; case std::errc::invalid_argument: std::cout << "Invalid argument!" << std::endl; break; default: std::cout << "Error: res.ec = " << int(res.ec) << std::endl; } } std::cout << "\n---------------------------------------------------------------------------------------------------"; std::cout << "\nLet's demonstrate string conversion to double using the 'std::from_chars' function "; std::cout << "\n---------------------------------------------------------------------------------------------------\n"; std::array<std::string, 8=""> arrDoubleNums = { std::string("4.02"), std::string("7e+5"), std::string("A.C"), std::string("-67.90000"), std::string("10.9000000000000000000000"), std::string("20.9e+0"), std::string("-20.9e+1"), std::string("-10.1") }; double stored_dw_value { 0.0 }; for (auto& e : arrDoubleNums) { std::cout << "Array element = " << e << std::endl; const auto res = std::from_chars(e.data(), e.data() + e.size(), stored_dw_value, std::chars_format::general); switch (res.ec) { case std::errc(): std::cout << "Stored value: " << stored_dw_value << ", Number of characters = " << res.ptr - e.data() << std::endl; break; case std::errc::result_out_of_range: std::cout << "Result out of range! Number of characters = " << res.ptr - e.data() << std::endl; break; case std::errc::invalid_argument: std::cout << "Invalid argument!" << std::endl; break; default: std::cout << "Error: res.ec = " << int(res.ec) << std::endl; } } return 0; }
请注意,在第二次调用std::from_chars时,最后参数我们使用额外的std::chars_format::general,以支持不同的数字格式串。
std::chars_format::general(在 <charconv> 中定义)用于指定std::to_chars 和std::from_chars 函数的浮点格式的 。
让我们看看上面代码的输出,将字符串转换为整数和双精度:
现在让我们做相反的操作,即考虑一个示例,说明我们如何使用std::to_chars来将整数和浮点数转换为字符串:
#include <iostream> #include <string> #include <array> #include <charconv> // to_chars int main() { std::cout << "--------------------------------------------------------------------------------------------------------------------\n"; std::cout << "Let's demonstrate the conversion of long values to a string (5 characters long) using the 'std::to_chars' function " << std::endl; std::cout << "--------------------------------------------------------------------------------------------------------------------\n"; // construction uses aggregate initialization std::array<long, 8=""> arrIntNums = { -123,-1234,-12345, -1234567890, 123, 1234, 1234567890, 987654321}; std::string stored_str_value{ "00000" }; for (auto& e : arrIntNums) { stored_str_value = "00000"; std::cout << "Array element = " << e << std::endl; const auto res = std::to_chars(stored_str_value.data(), stored_str_value.data() + stored_str_value.size(), e /*, int base = 10*/); switch (res.ec) { case std::errc(): std::cout << "Stored value: " << stored_str_value << ", Number of characters = " << res.ptr - stored_str_value.data() << std::endl; break; case std::errc::result_out_of_range: std::cout << "Result out of range! Number of characters = " << res.ptr - stored_str_value.data() << std::endl; break; case std::errc::value_too_large: std::cout << "Value too large!" << std::endl; break; default: std::cout << "Error: res.ec = " << int(res.ec) << std::endl; } } std::cout << "--------------------------------------------------------------------------------------------------------------------\n"; std::cout << "Let's demonstrate the conversion of double values to a string (5 characters long) using the 'std::to_chars' function " << std::endl; std::cout << "--------------------------------------------------------------------------------------------------------------------\n"; // construction uses aggregate initialization std::array<double, 8> arrDoubleNums = {4.02, 7e+5, 5, -67.90000, 10.9000000000000000000101,20.9e+0,-20.9e+1,-10.1}; for (auto& e : arrDoubleNums) { stored_str_value = "00000"; std::cout << "Array element = " << e << std::endl; const auto res = std::to_chars(stored_str_value.data(), stored_str_value.data() + stored_str_value.size(), e, std::chars_format::general); switch (res.ec) { case std::errc(): std::cout << "Stored value: " << stored_str_value << ", Number of characters = " << res.ptr - stored_str_value.data() << std::endl; break; case std::errc::result_out_of_range: std::cout << "Result out of range! Number of characters = " << res.ptr - stored_str_value.data() << std::endl; break; case std::errc::value_too_large: std::cout << "Value too large!" << std::endl; break; default: std::cout << "Error: res.ec = " << int(res.ec) << std::endl; } } return 0; }
看里面的代码拐来拐去,真是不想用,不过看性能提升这么明显,还是忍耐下吧。STL的风格就是尖括号多,函数多,不能直接看到指针。