为什么在编译器已知长度时不优化字符串赋值?

时间:2010-01-31 22:57:56

标签: c++ visual-c++ string compiler-optimization stdstring

我今天玩了一些计时代码并发现当将一个字符串文字与std :: string一起使用时,它的速度提高了大约10%(使用一个短的12个字符串字符串,因此大字符串的差异更大)使用已知长度的文字(使用sizeof运算符)而不是。 (仅使用VC9编译器进行测试,因此我猜其他编译器可能会做得更好)。

std::string a("Hello World!");
std::string b("Hello World!", sizeof("Hello World!");//10% faster in my tests

现在我怀疑的原因是它必须调用strlen(VC9进入汇编,这不是我的强点所以我不能100%肯定)来获取字符串长度,然后像第二种情况一样无论如何。

考虑到std :: string已经存在了多长时间,以及在实际程序中第一种情况(特别是如果你包括+,=,+ =等操作符和等效方法)有多常见,为什么它不会优化第一种情况进入第二种情况?这似乎是一个非常简单的,只要说它是一个std :: basic_string对象和一个文字,编译它就好像它被写成b?

2 个答案:

答案 0 :(得分:4)

第一个无法优化到第二个。在第一个,字符串的长度是未知的,因此必须计算,在第二个你告诉它多长时间,所以不需要计算。

使用sizeof()没有区别 - 这也是在编译时计算的。第一种情况使用的构造函数是:

 string( const char * s );

这个构造函数无法检测到它是否被赋予字符串文字,更不用说在编译时计算它的长度了。

此外,在实际代码中,从C风格的字符串文字构造字符串相对较少 - 它根本不值得优化。如果你确实需要优化它,只需重写:

while( BIGLOOP ) {
   string s( "foobar" );
   ...
}

为:

string f( "foobar" );
while( BIGLOOP ) {
   string s( f );
   ...
}

答案 1 :(得分:2)

编译器无疑可以做到这样的事情,实际上你可以自己做:

template<size_t SIZE>
std::string f(const char(&c)[SIZE]) {
    return std::string(c, SIZE);
}

int main() {
    std::string s = f("Hello");
    cout << s;
}

或甚至使用自定义派生类型(尽管std :: string没有理由不能使用此构造函数):

class mystring : public string {
public:
    template<size_t SIZE>
    mystring(const char(&c)[SIZE]) : string(c, SIZE) {}
};

int main() {
    mystring s("Hello");
    cout << s;
}

一个很大的缺点是为每个不同的字符串大小生成了一个函数/构造函数的版本,如果编译器不能很好地处理模板提升,整个类甚至可以复制......这些可能是交易 - 在某些情况下会破坏。