You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Transform视图版大小写无关字符串相等判断性能逊于投影版?

摘要

在判断两个字符串是否大小写无关相等时,为何以下代码

bool rangeV3WithTransformViews(std::string_view str1, std::string_view str2) {
    return equal(str1 | transform(tolowercase),
                 str2 | transform(tolowercase));
}

的性能远低于这段代码?

bool rangeV3WithProj(std::string_view str1, std::string_view str2) {
    return equal(str1, str2, std::equal_to{}, tolowercase, tolowercase);
}

后者在GCC 13.2搭配-O3编译选项时,生成的汇编代码与底层C风格实现完全一致:

#define to_lower_ascii(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + 32 : (c))

int cstyle(const char* str1, const char* str2) {
    while (*str1 != '\0' && *str2 != '\0' && to_lower_ascii(*str1) == to_lower_ascii(*str2)) {
        str1++;
        str2++;
    }
    return to_lower_ascii(*str1) - to_lower_ascii(*str2);
}

详细说明

我最初因实现大小写无关字符串相等需编写冗长、底层且可读性差的代码而沮丧,于是尝试基于range编写实现,最初得到上述第一个方案,却被quick-bench.com证实其性能较差。有两点结论清晰:

  • GCC(至少QuickBench上的版本及对应编译选项)可将rangeV3WithProj编译为与cstyle完全一致的汇编,说明编译器能完全看透该抽象;
  • rangeV3WithProj比rangeV3WithTransformViews更简洁、抽象层级更少,理论上不应更慢。

我原本预期编译器也能对rangeV3WithTransformViews做同样优化,但实际并未实现。因此提出以下问题:

  • 是什么导致第一个代码片段本质上比第二个更慢?
  • 是什么阻碍编译器为第一个片段生成与后两者一致的汇编代码?

我认为问题出在transform上,但为何它会导致汇编差异与性能下降?毕竟输入是std::string_view,属于sized_range,transform对其处理后仍返回sized_range,不存在循环长度未知的问题。

注意事项

我并不清楚QuickBench的具体运作机制,但令我疑惑的是,即便传入-O3 -std=c++20选项,Compiler Explorer生成的rangeV3WithProj与cstyle汇编代码并不完全一致。


(¹) 如果我在代码中埋下错误,比如将某些!=改为==、32改为34,或是最后一处str2应为str1,你能发现吗?

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:23:26