创建空std::string的最佳方式

创建一个空的std::string对象有多种方式,常见的有以下两种:

第一种是直接使用std::string的默认构造函数,例如:

1
2
3
4
5
6
7
//创建变量
std::string string;

//从函数返回
std::string GetEmptyString() {
return std::string();
}

第二种是由空的C字符串字面量转换,不论是显式的还是隐式的转换,例如:

1
2
3
4
5
6
7
8
//创建变量
std::string string1("");
std::string string2 = "";

//从函数返回
std::string GetEmptyString() {
return "";
}

这两种方式的结果都是一样的,但是过程却有一点不同。第一种方式直截了当地创建一个空std::string对象,没有多余的操作;而第二种方式则多了一个转换过程——它要通过strlen之类的函数计算出字符串的长度。即便是空字符串,这个转换过程也会造成一些开销。所以,从理论上来说,第二种方式的性能会比较差。具体差了多少呢?可以使用以下代码进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <sstream>
#include <string>

int main() {

const int Count = 100000000;

std::ostringstream os;

std::clock_t begin_time = clock();

for (int count = 0; count < Count; ++count) {
std::string str;
os << str;
}

std::clock_t end_time = clock();
std::cout << double(end_time - begin_time) / CLOCKS_PER_SEC << std::endl;

begin_time = clock();

for (int count = 0; count < Count; ++count) {
std::string str("");
os << str;
}

end_time = clock();
std::cout << double(end_time - begin_time) / CLOCKS_PER_SEC << std::endl;

std::cout << os.str() << std::endl;
}

分别用两种方式创建std::string对象一亿次,输出两者的耗时。每次创建字符串之后,都会把它输出到一个std::ostringstream对象中,这是为了避免在release模式下编译器把无实际作用的for循环优化掉。以下是在XCode中运行的输出结果:

1.47766
1.97115

可见,第二种方式确实会比第一种方式慢,不过差距十分微小:在创建一亿个std::string对象的级别下才慢了0.5秒,几乎可以忽略不计。尽管如此,对于追求效率的程序员来说,显然第一种方式更胜一筹。