用于替换std :: string中字符的最快(也是最安全)的方法

时间:2015-11-24 12:17:32

标签: 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);

所以最快的方式似乎是(5),但我担心这种方法可能无法正常使用&#34; copy-on-write&#34;许多编译器使用的std::string优化。

恕我直言(5)也更具可读性。

我想知道为什么(4)的速度是(3)的两倍,我认为operator[]的{​​{1}}已经相当优化......

更新

阅读评论后,我已更新我的代码以使用Google基准库,而(3)和(4)的结果似乎相同,其他差异仍然适用:

std::string

所以(3)和(4)的差异消失了,但其余的结果是相同的:)

1 个答案:

答案 0 :(得分:2)

至少从C ++ 11开始,使用memcpy的方法符合标准,因为

  1. this answer中所述,不允许std::string的写时复制实施,因为它违反了迭代器/引用要求的标准无效。

  2. std::string的字符存储在连续的内存中,引用21.4.1.5:

      

    basic_string对象中的char类对象应连续存储。也就是说,对于任何basic_string   对象s,身份&amp; *(s.begin()+ n)==&amp; * s.begin()+ n应保留n的所有值,使得0   &lt; = n&lt; s.size()。

  3. 因此,它是您列表中方法中最快的符合标准(至少根据您的基准测试结果)。

    事实上,即使使用non-standard-compliant implementation进行写时复制也应该是安全的,因为非const 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";
    

    打印

    0x1782028 0x1782028
    0x1782028 0x1782058
    

    当我使用gcc 4.8.4和相当旧版本的libstdc ++编译它并运行时。请注意,在调用非const operator[]之后,指针是不同的,这意味着数据已被复制。

    知道非const operator[]在COW实现中做了一些检查,通过调用const operator[]可能会加速更多:

    const std::string &crep = rep;
    memcpy(&r5[3], &crep[1], 7);
    

    在我的系统上确实更快:

    Benchmark              Time(ns)    CPU(ns) Iterations
    -----------------------------------------------------
    bench_memcpy_const            2          2  314215561 
    bench_memcpy                  3          3  276899830