精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
锐英源精品开源心得,禁止全文或局部转载,禁止任何形式的非法使用,侵权必究
本文介绍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的风格就是尖括号多,函数多,不能直接看到指针。