【问题标题】:Does sorting a vector of std::wstring actually rewrite the raw string data?对 std::wstring 的向量进行排序实际上会重写原始字符串数据吗?
【发布时间】:2018-01-09 09:54:51
【问题描述】:

让我们对 100 万个字符串中的 vector 进行排序:

std::vector<std::wstring> v;           
// fill the vector
std::sort(v.begin(), v.end());

是吗:

  1. 用新的wstrings重写向量,包含wstring结构本身的几个字节+指向未修改的实际原始数据的指针,不重写/移动实际字符原始数据

或

  1. 用新的wstrings 重写向量实际字符原始数据也被重写/移动?

如果字符串平均有 100 个字符长,我可以想象 2. 会比 1 慢很多。

这两种情况中哪一种在 C++03 上是正确的?在 C++11 上?

【问题讨论】:

    标签: c++ string sorting c++11 vector


    【解决方案1】:

    虽然我不确定第一个选项是否能保证,但我很确定它会移动大小恒定的std::wstring 结构(它们不依赖于字符串的大小)。

    表示字符串的字节不在其结构中,只有一个指向它们分配的内存区域的指针。

    【讨论】:

    • 是的,问题确实是:它是否会为每个字符串重写 sizeof(std::wstring) 字节(通常 = 24 或 32),但保持分配的相同指针/相同的内存区域(解决方案 1)?或者它是否为字符串数据重新分配新字节(解决方案2)?
    • 肯定是第一个选项。不仅更快,而且更通用,因为第二个选项将是 C++ 中“深度移动事物”的一种奇怪形式。
    【解决方案2】:

    std::wstring 复制/移动构造函数或最好的交换方法(取决于实现)应该处理这个并交换内部指针而不是数据。由于 C++03 标准版本在这种情况下不会影响性能,因此相关的 std::basic_string 属性没有更改。

    编译器和它的标准库实现然而会。另请记住,如果您关心性能,您应该运行基准测试并使用分析器。

    【讨论】:

      【解决方案3】:

      1. 和 2. 都不是。

      std::sort 与 (std::)swap 交换元素。没有创建新元素(与您的 1. 建议不同)。只有现有的会被修改。但是,不需要触摸字符数据(与您的 2. 建议不同)。只需将大小、迭代器、指针等数据从一个字符串复制到另一个字符串。虽然,这取决于实施。唯一的保证是复杂性是恒定的。

      就标准字符串而言,这在 C++11 中没有改变。但是,依赖于默认 std::swap 的自定义类型的排序效率更高,因为更高效的泛型 std::swap 受益于移动语义。

      【讨论】:

      • 谢谢。 Simply the size, iterator, pointer etc. data is copied from one string to the other 这很棒。那么是否保证实际的原始字符数据永远不会被重写? (在 c++ 草案或其他地方是否有关于这方面的资料?)
      • @Basj 无法保证触摸内存。特别是,使用小字符串优化的实现在交换小字符串时肯定会复制字符数据。但复杂性保证是恒定的,这是我所关心的。
      • 好吧,那很酷。这些问题的参考资料在哪里,并提供有关此的详细信息?我在std::swap 上没有发现任何关于数据的哪一部分被重写的信息。
      【解决方案4】:

      std::wstring 被允许并且通常确实使用小字符串优化。这意味着对于短字符串,字符存储在内std::wstring。对于较长的字符串,std::wstring 会在空闲存储区(也就是堆)中存储一个指向字符缓冲区的指针。

      当您对std::wstrings 的容器进行排序时,std::wstrings 在概念上会四处移动。空闲存储上的字符缓冲区从一个std::wstring 实例传递到另一个实例,并且从不复制或修改。可以修改和复制“小字符串”案例。

      在 C++11 和 C++03 中都是如此。

      在 C++11 之前,std::wstring 的一些实现使用了写时复制智能指针。 C++11 加强了对 std::basic_string 的要求,这使得此类实现是非法的。 COW(写时复制)智能指针字符串很少使用 SBO(我猜他们可以)。

      std::sort 是根据std::swap 编写的,它专门用于std::basic_string 或使用std::move 来有效地不重新分配缓冲区。

      【讨论】:

        猜你喜欢
        • 2017-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-15
        • 1970-01-01
        • 2019-03-31
        • 2014-09-19
        • 1970-01-01
        相关资源
        最近更新 更多