编译器通常对字符串有特殊的优化吗?

Do compilers usually have special optimizations for strings?

本文关键字:优化 字符串 编译器      更新时间:2023-10-16

很多时候你会看到像

std::map<std::string, somethingelse> m_named_objects;

std::string state;
//...
if(state == "EXIT")
   exit();
else if(state == "california")
   hot();

中,人们使用字符串纯粹是为了使内容更具可读性。同样的事情也可以很容易地通过整数id来实现。

现代编译器(msvc, g++等)通常可以为这些类型的情况使用特殊的优化吗?或者由于性能不佳或其他原因应该避免这种情况?

现代编译器(msvc, g++等)通常可以为这些类型的情况使用特殊的优化吗?

据我所知,编译器不会进行这种优化。这绝对不是一个"标准"的优化。

…人们使用字符串纯粹是为了让东西更容易读。

至少对于你的第二种情况,在我看来,枚举更可读,可以更快(因为整数比较相对于字符串比较相当便宜)。

enum State
{
    Alabama,
    Alaska,
    Arizona,
    Arkansas, 
    California,
    Colorado,
    Connecticut,
    Delaware,
    // ... More
};
// ...
State state = California;
if(state == California) { /* true */ }

库可以。

编译器可以通过别名共享/相同的静态字符串(假设它们确实被视为常量)进行优化。

我目前所知道的所有c++标准库实现都采用了"小字符串优化",这意味着不需要为小字符串分配额外的堆;例如

std::string a("small");

将完全自动(堆栈)分配-在高度优化的情况下甚至可能分配寄存器(?)


如果你需要非常快速的字符串查找,并且可以花一些时间来构建你的数据结构,请查看Tries (WP: Trie, Radix_tree)

就插入式替换而言通常可以通过使用适当调优的哈希映射而不是基于rb树的哈希映射来获得很多:

<罢工>

std::map<std::string, somethingelse> m_named_objects;

替换

std::unordered_map<std::string, somethingelse> m_named_objects;

快乐

在给出的示例中,编译器通常无法优化,因为内容依赖于运行时。

std::map<std::string, int>不具有最理想的性能特征,因为std::string上的operator<()相对昂贵。

字符串的优化是针对库的,而不是编译器的。如果想要类似字符串的标识符,枚举是一种可能。但是一个更好的,特别是对于打印和调试来说,是一个固定长度的标识符字符串类。

它可以转换为const char *std::string,但是它的内存分配为零。相反,它只是一个32个字符(或任何你想要的)数组的包装器。

最好的部分是,因为它是一个标识符,你不关心ASCII字符间的比较。operator<可以将32个字符的数组读取为8个uint32_t s,甚至读取为4个uint64_t s。您所需要的只是排序,而不是特定的排序。operator==可以做类似的测试。

这是一个非常简单的类。如果需要不区分大小写的比较,只需在将字符串复制到对象中时将其转换为小写即可。

如果您需要超过31个字节的字符串(一个用于终止符),那么我建议将字符串截断到合适的大小。但是从给定字符串的中间截断,而不是末尾。标识符的开头和结尾往往比中间更加独特。您甚至可以在截断的字符串中放入一些特殊字符来标识它是截断的版本。

也可以采用这个想法并在字符串中放入哈希值。因此,前4个字节将是原始字符串的散列,而不是截断的散列。比较测试将只使用哈希值,其他28个字节用于使其可读。