C++性能优化神器:它 比 std::stoi 快 3 倍!

1. 背景 我最近在项目中遇到一个需求——针对同一个类型的接口,需要支持传入多种数据类型,大概形式如下,代码语言:javascript代码运行次数:0运行复制void UpdateValue(const char* value_name,i

C++性能优化神器:它 比 std::stoi 快 3 倍!

1. 背景

我最近在项目中遇到一个需求——针对同一个类型的接口,需要支持传入多种数据类型,大概形式如下,

代码语言:javascript代码运行次数:0运行复制
void UpdateValue(const char* value_name,int value);
void UpdateValue(const char* value_name,double value);
void UpdateValue(const char* value_name,const char* value);

如果是C++接口,可以用重载用模板,但是我需要提供C接口,这些特性都用不了。虽然可以采用如下的方案:

代码语言:javascript代码运行次数:0运行复制
void UpdateIntValue(const char* value_name,int value);
void UpdateDoubleValue(const char* value_name,double value);
void UpdateCharValue(const char* value_name,const char* value);

但是这样的话,每次有新的类型,都需要增加新的接口,每次增加新的接口,都意味着使用库的铜须需要重新编译、集成,这套方案显然是不成熟的。 通过思考发现,我可以通过value_name知晓value的类型,所以可以考虑如下的方案:

代码语言:javascript代码运行次数:0运行复制
void UpdateValue(const char* value_name, const char* value);

这样提供的接口是稳定的,不会因为类型增加而改变。但是这样又引入了一个新的问题,就是如何将char*转换为对应的类型,比如int、double等。

通常情况下,我们会使用std::stoistd::stof等函数,但是这些函数存在一些问题:

  • 性能问题:std::stoi() 和 std::stof() 需要将输入转换为 std::string,这可能导致额外的堆分配和数据拷贝,从而降低性能。
  • **依赖 std::locale**:许多标准转换函数受 std::locale 影响,可能导致额外的性能开销。
  • 不灵活std::stoi() 只能处理 std::string,而 std::strtol() / std::strtof() 需要 C 风格字符串,使用起来不够现代化。

对于依赖和不灵活,我到可以退而求其次,但是性能一直是我特别关注的。后来我发现了charconv,它是一个用于字符数组与数值类型之间转换的库,可以高效地进行数值解析和格式化。

当前可查的 std::from_chars()std::stoi() / std::stof() 的性能对比结果如下:

方法

解析整数 (100 万次)

解析浮点数 (100 万次)

std::stoi

120 ms

-

std::from_chars

35 ms

90 ms (C++20)

std::strtol

100 ms

-

std::strtod

-

180 ms

从数据来看,std::from_chars() 解析 整数比 std::stoi() 快 3~4 倍,解析 浮点数比 std::strtod() 快 2 倍,这对性能敏感的应用来说是一个巨大的提升。

2. charconv

<charconv>C++17 引入,提供 std::to_chars()std::from_chars(),用于在 数值类型和字符数组 之间进行高效转换。 其使用非常简单,如下仅以整数为例,其余类型雷同。

整数转字符串 (to_chars)

代码语言:javascript代码运行次数:0运行复制
#include <charconv>
#include <iostream>
#include <array>

int main() {
    std::array<char, 20> buffer; // 预分配足够大的缓冲区
    int value = 12345;
    
    auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value);
    
    if (ec == std::errc{}) {
        std::cout << "Converted: " << std::string(buffer.data(), ptr) << std::endl;
    } else {
        std::cerr << "Conversion failed" << std::endl;
    }
}

字符串转整数 (from_chars)

代码语言:javascript代码运行次数:0运行复制
#include <charconv>
#include <iostream>

int main() {
    constchar* str = "12345";
    int value;
    
    auto [ptr, ec] = std::from_chars(str, str + std::strlen(str), value);
    
    if (ec == std::errc{}) {
        std::cout << "Parsed value: " << value << std::endl;
    } else {
        std::cerr << "Parsing failed" << std::endl;
    }
}

3. 实战建议

虽然 charconv 性能强大,但在使用时需要注意以下几点:

  • 负数解析: std::from_chars() 解析数字时,直到C++20后才支持解析负数,如果项目中不能使用C++20时,需要手动处理:
代码语言:javascript代码运行次数:0运行复制
const char* str = "-123";
int value;

if (*str == '-') {
    auto [ptr, ec] = std::from_chars(str + 1, str + std::strlen(str), value);
    value = -value; // 手动处理负号
}
  • 需要确保缓冲区足够大:使用 std::to_chars() 时,需要保证 char 数组大小足够,否则可能会转换失败。

4. 总结

std::charconv 提供了高效数值转换方法,不仅可以显著提高性能,还避免了 std:locale 影响。但是使用时还需要注意如上的实战建议。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-03-31,如有侵权请联系 cloudcommunity@tencent 删除c++std接口性能性能优化

发布者:admin,转转请注明出处:http://www.yc00.com/web/1748041479a4722747.html

相关推荐

  • C++性能优化神器:它 比 std::stoi 快 3 倍!

    1. 背景 我最近在项目中遇到一个需求——针对同一个类型的接口,需要支持传入多种数据类型,大概形式如下,代码语言:javascript代码运行次数:0运行复制void UpdateValue(const char* value_name,i

    4小时前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信