gab*_*bry 8 c++ string optimization
我必须在长字符串中替换一些(固定)字符数量:我想知道什么是最快但标准的符合方式.
这是一个包含6种不同方法的示例代码; 在方法的注释中,我添加了在测试环境中执行操作100万次的时间(以毫秒为单位),并启用了优化.
const char* pluto = "Cia1234567Ciao!";
std::string rep = "87654321";
std::string r1 = pluto, r2 = pluto, r3 = pluto, r4 = pluto, r5 = pluto, r6 = pluto;
// (1) 300 msec
r1.replace(3, 7, rep.substr(1));
// (2) 40 msec
std::copy(rep.begin() + 1, rep.end(), r2.begin() + 3);
// (3) 32 msec
for (int i = 1; i < 8; ++i)
r3[2 + i] = rep[i];
// (4) 14 msec
{
const char *c = rep.c_str() + 1;
for (int i = 0; i < 7; ++i)
r4[3 + i] = *c++;
}
// (5) 3 msec (BEST)
memcpy(&r5[3], &rep[1], 7);
// (6) 100 msec
r6.replace(3, 7, rep.c_str() + 1);
Run Code Online (Sandbox Code Playgroud)
所以最快的方式似乎是(5),但我担心这种方法可能无法正常使用std::string
许多编译器使用的"写时复制" 优化.
恕我直言(5)也更具可读性.
我不知道为什么(4)快两倍,(3),我认为operator[]
的std::string
是相当优化...
更新:
阅读评论后,我更新了我的代码以使用谷歌基准库,(3)和(4)的结果似乎是相同的,其他差异仍然适用:
Run on (2 X 3000 MHz CPU s)
2015-11-24 14:46:50
Benchmark Time(ns) CPU(ns) Iterations
-----------------------------------------------------------
(1) bench_replace_substr 293 264 2651515
(2) bench_std_copy 39 39 19662921
(3) bench_op_bracket 15 15 39772727
(4) bench_op_bracket_2 15 15 44871795
(5) bench_memcpy 4 4 75000000
(6) bench_replace 80 80 8333333
Run Code Online (Sandbox Code Playgroud)
所以(3)和(4)的差异消失了,但其余的结果是相同的:)
使用的方法memcpy
至少从 C++11 起就符合标准,因为
正如本答案std::string
中所解释的,不允许写入时复制实现,因为它违反了迭代器/引用的标准失效要求。
std::string
的字符存储在连续的内存中,引用21.4.1.5:
basic_string 对象中的类字符对象应连续存储。也就是说,对于任何 basic_string 对象 s,恒等式 &*(s.begin() + n) == &*s.begin() + n 对于 n 的所有值都成立,使得 0 <= n < s.size ()。
因此,它是您列表中最快的符合标准的方法(至少根据您的基准测试结果)。
事实上,即使使用不符合标准的写时复制实现,这也应该是安全的,因为非常量operator[]
应该复制字符串,例如:
std::string s1("foo");
std::string s2 = s1;
std::cout << static_cast<const void*>(s1.data()) << " "
<< static_cast<const void*>(s2.data()) << "\n";
s2[0];
std::cout << static_cast<const void*>(s1.data()) << " "
<< static_cast<const void*>(s2.data()) << "\n";
Run Code Online (Sandbox Code Playgroud)
印刷
0x1782028 0x1782028
0x1782028 0x1782058
Run Code Online (Sandbox Code Playgroud)
当我使用 gcc 4.8.4 和相当旧版本的 libstdc++ 编译它并运行时。请注意,调用非 const 后指针会有所不同,operator[]
这意味着数据已被复制。
知道 non-constoperator[]
在 COW 实现中做了一些检查,通过调用 const 可能会加快速度operator[]
:
const std::string &crep = rep;
memcpy(&r5[3], &crep[1], 7);
Run Code Online (Sandbox Code Playgroud)
这在我的系统上确实更快:
Benchmark Time(ns) CPU(ns) Iterations
-----------------------------------------------------
bench_memcpy_const 2 2 314215561
bench_memcpy 3 3 276899830
Run Code Online (Sandbox Code Playgroud)