我有一个简单的场景。我需要将两个C字符串连接成一个std::string
。我决定以两种方式之一做到这一点:
void ProcessEvent(char const* pName) {
std::string fullName;
fullName.reserve(50); // Ensure minimal reallocations for small event names (50 is an arbitrary limit).
fullName += "com.domain.events.";
fullName += pName;
// Use fullName as needed
}
void ProcessEvent(char const* pName) {
std::ostringstream ss;
ss << "com.domain.events." << pName;
std::string fullName{ss.str()};
// Use fullName as needed
}
我更喜欢解决方案2,因为代码更自然。解决方案1似乎是对性能测试中可测量瓶颈的响应。但是,解决方案1的存在有两个原因:
为了简单起见,优先考虑解决方案2是否过早的悲观化?或者选择解决方案1是否为过早的优化?我想知道我是否过于担心STL流。
答案 0 :(得分:11)
使用以下功能进行快速测试:
void func1(const char* text) {
std::string s;
s.reserve(50);
s += "com.domain.event.";
s += text;
}
void func2(const char* text) {
std::ostringstream oss;
oss << "com.domain.event." << text;
std::string s = oss.str();
}
循环运行每100 000次,在我的计算机上平均得到以下结果(使用gcc-4.9.1):
func1:37毫秒
func2:87毫秒
也就是说,func1
的速度是原来的两倍多。
话虽这么说,我建议使用最清晰,最易读的语法,直到你真的需要这个性能。首先实现可测试程序,然后优化它是否太慢。
修改强>
正如@Ken P所建议的那样:
void func3(const char* text) {
std::string s = "com.domain.event" + std::string{text};
}
func3:27毫秒
最简单的解决方案往往是最快的。
答案 1 :(得分:0)
你没有提到在字符串中没有预先分配任何东西的第三种选择,只是让优化器做他们最擅长的事情。
鉴于这两项功能,func1
和func3
:
void func1(const char* text) {
std::string s;
s.reserve(50);
s += "com.domain.event.";
s += text;
std::cout << s;
}
void func3(const char* text) {
std::string s;
s += "com.domain.event.";
s += text;
std::cout << s;
}
在http://goo.gl/m8h2Ks的示例中可以看出,func1的gcc程序集仅用于为50个字符保留空间将比func3中没有预分配时添加额外的3个指令。其中一个调用是一个字符串追加调用,这反过来会产生一些开销:
leaq 16(%rsp), %rdi
movl $50, %esi
call std::basic_string<char>::append(char const*, unsigned long)
单独查看代码并不能保证func3比func1快,只是因为它的指令较少。缓存和其他因素也有助于实际表现,只有通过衡量才能正确评估,正如其他人指出的那样。