(免责声明:我不知道C++标准可能对此有何规定...我知道,我很糟糕)
在操作非常大的字符串时,我注意到std::string使用了写时复制技术。我成功编写了最简循环以重现观察到的行为,例如以下循环运行得异常快速:
#include <string>
using std::string;
int main(void) {
string basestr(1024 * 1024 * 10, 'A');
for (int i = 0; i < 100; i++) {
string a_copy = basestr;
}
}
在循环体中添加一次写操作a_copy[1] = 'B';
后,实际上进行了一次复制,程序运行时间从几毫秒变为了0.3秒。100个写操作使其变慢了约100倍。
但之后情况变得奇怪起来。我的某些字符串只读取而没有写入,但这并没有反映在执行时间上,执行时间几乎完全与字符串操作的数量成正比。经过一些挖掘,我发现仅从字符串中读取数据仍然会导致性能下降,因此我推断 GNU STL 字符串使用了按需拷贝(copy-on-read)的技术。
#include <string>
using std::string;
int main(void) {
string basestr(1024 * 1024 * 10, 'A');
for (int i = 0; i < 100; i++) {
string a_copy = basestr;
a_copy[99]; // this also ran in 0.3s!
}
}
在我发现这个问题后兴奋了一段时间,但随后发现从基础字符串中使用operator[]进行读取也需要0.3秒的时间,我对此并不完全满意。STL字符串确实是按照读取时复制(copy-on-read)的吗?或者它们是否允许写入时复制(copy-on-write)?我认为operator[]有一些防范措施来防止其返回的引用被保留并在稍后被写入,这真的是这种情况吗?如果不是,那么真正发生了什么?如果有人可以指出C++标准中的相关部分,那也将不胜感激。
供参考,我使用的是g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
和GNU STL。
[]
时的读取和写入操作。 - peterchen