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

时间:2011-08-31 20:01:28

标签: c++ string compiler-optimization stdstring

很多时候你会看到像

这样的东西
std::map<std::string, somethingelse> m_named_objects;

std::string state;

//...

if(state == "EXIT")
   exit();
else if(state == "california")
   hot();

人们纯粹使用字符串来使字母更具可读性。使用整数ID可以很容易地实现同样的目的。

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

4 个答案:

答案 0 :(得分:6)

  

现代编译器(msvc,g ++等)通常可以对这些类型的案例采用特殊优化吗?

据我所知,编译器不进行这些优化。这绝对不是“标准”优化。

  

......人们纯粹使用字符串来使字母更具可读性。

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

enum State
{
    Alabama,
    Alaska,
    Arizona,
    Arkansas, 
    California,
    Colorado,
    Connecticut,
    Delaware,
    // ... More
};

// ...

State state = California;
if(state == California) { /* true */ }

答案 1 :(得分:1)

图书馆。

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

我目前所知道的所有C ++标准库实现都采用“小字符串优化”,这意味着小字符串不需要额外的堆分配;即

std::string a("small");

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


如果您需要超快的字符串查找并且可以花费一些时间来构建数据结构,请查看Tries(WP:TrieRadix_tree

对于直接替换,通常使用正确调整的哈希映射而不是基于RB树的哈希映射可以获得很多:

<击>

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

<击>

替换为

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

快乐

答案 2 :(得分:0)

在给出的示例中,编译器通常无法进行优化,因为内容与运行时有关。

std::map<std::string, int>没有最理想的性能特征,operator<()上的std::string相对较贵。

答案 3 :(得分:0)

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

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

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

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

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

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