代码之家  ›  专栏  ›  技术社区  ›  Passer By

STD:字符串移动的实现

  •  12
  • Passer By  · 技术社区  · 6 年前

    我在调查搬家的表现 std::string . 很长一段时间以来,我一直认为字符串移动几乎是自由的,认为编译器将内联所有内容,它只涉及一些便宜的赋值。

    事实上,我的移动思维模式

    string& operator=(string&& rhs) noexcept
    {
        swap(*this, rhs);
        return *this;
    }
    
    friend void swap(string& x, string& y) noexcept
    {
        // for disposition only
        unsigned char buf[sizeof(string)];
        memcpy(buf, &x, sizeof(string));
        memcpy(&x, &y, sizeof(string));
        memcpy(&y, buf, sizeof(string));
    }
    

    据我所知,如果 memcpy 更改为分配单个字段。

    令我惊讶的是,海湾合作委员会实施的搬迁涉及到 creating a new string and might possibly throw due to the allocations despite being noexcept .

    这是否符合要求?同样重要的是,我不应该认为搬家几乎是免费的吗?


    令人困惑的是, std::vector<char> compiles down 我所期待的。

    clang's implementation 虽然有可疑的 std::string::reserve

    2 回复  |  直到 6 年前
        1
  •  1
  •   geza    6 年前

    我只分析过GCC的版本。下面是发生的事情:代码处理不同类型的分配器。如果分配器具有 _S_propagate_on_move_assign _S_always_equal ,然后移动几乎是免费的,正如您所期望的。这是 if 移动中 operator= :

    if (!__str._M_is_local()
        && (_Alloc_traits::_S_propagate_on_move_assign()
          || _Alloc_traits::_S_always_equal()))
              // cheap move
    else assign(__str);
    

    如果条件是真的( _M_is_local() 表示小字符串,说明 here ,那么这一举措是便宜的。

    如果它是假的,那么它调用 正常的 assign (不是移动的那个)。在以下情况下:

    • 绳子很小,所以 分配 会做一个简单的memcpy(便宜)
    • 或者分配器没有这个特性 始终相等 也不 移动时传播分配 ,所以分配 将分配 (不便宜)

    这是什么意思?

    这意味着,如果您使用缺省分配器(或前面提到的具有特性的任何分配器),那么 移动仍然几乎是免费的 .

    另一方面,生成的代码是不必要的巨大,我认为可以改进。它应该有一个单独的代码来处理通常的分配器,或者有一个更好的 分配 代码(问题是 分配 不检查 _ m_是本地的 ,但它执行容量检查,因此编译器无法决定是否需要分配,因此它不必要地将分配代码路径放入可执行文件中-您可以在源代码中查看确切的详细信息)。

        2
  •  0
  •   Maxim Egorushkin    6 年前

    这不是一个答案,但这是C++ 11的新实现 std::string 没有参考计数器和小串优化导致大量组装。特别是,小字符串优化会导致4个分支处理移动分配的源和目标长度的4种不同组合。

    什么时候? -D_GLIBCXX_USE_CXX11_ABI=0 选项添加到使用前C++- 11 STD::字符串 带有参考计数器和非小串优化 the assembly code looks much better .


    我不应该认为搬家几乎是免费的吗?

    Nothing is Better than Copy or Move by Roger Orr 说话, slides 第47页上写着:

    复制和移动的比较

    • 许多人错误地认为行动是有效的“自由”
    • 拷贝和移动的性能差异很大
    • 当只需要传输对象的一部分以传输整个值时,移动比复制快